优雅地使用Git
序
前几天遇到一些关于权限和rebase的问题,另外,之前也有被多次问到在某某情况下怎么处理,某某操作是什么命令,某某命令怎么用等等的问题,当然,还有一些其他不常用的Git命令,但真正需要的时候又比较棘手,估计大部分人只会使用一些简单常规并且在正常流程下的命令,鉴于此,觉得还是有必要分享一下。
如果你已经是Git高手了,这篇博客对你意义不大,不过可以下方留言,补充更多的信息。如果你是从来没有使用过Git的,这篇博客也不太适合你,不过我会给出一些简单说明和入门教程的链接,如果你有兴趣学习的话,想必能够帮到你。如果你是Git新用户,或者使用Git有一段时间了,但经常会遇到一些棘手问题不知所措,那本博客应该会对你有一些帮助。
基本介绍
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
Git是一款免费且开源的分布式版本控制系统(DVCS),Git是由Linux之父Linus Torvalds在2005年创造出来最初用于管理Linux内核代码,解决与其他贡献者协同开发的问题,Git能以非常高效的方式管理各种规模的项目,分布式意味着每个人的电脑都是一个完整的版本控制库,并且工作时都不需要联网,相对于其他版本控制管理系统,优势不只是一个两个数量级,目前算是世界上最先进的分布式版本控制系统。
首先特别需要提一下Git的三种状态: committed(已提交), modified(已修改)和staged(已暂存),同时也需要理解一下git directory(Git版本库), working directory(工作区)和staging area(暂存区)。
- Git Directory(Repository): Git版本库,有一个
.git
的隐藏目录,即版本库,存放了元数据和数据库文件。 - Working Directory: 工作区,指正在工作的目录,
.git
版本库目录除外。 - Staging Area: 暂存区,在版本库中,一个包含待提交信息或缓存的文件。
通常,Git工作的一般流程为:
- 在工作区中添加或修改文件
- 将文件快照添加到暂存区中
- 将暂存区的文件提交并永久存入版本库
更多细节和原理介绍可以阅读 Git官网介绍,这里就不再赘述。
Git准备
首先必需要提出来的是,强烈建议使用CLI,不要总想着GUI,如果你能对你执行的操作有完全掌控,你不必担心出现一些非意料的问题,并且当你使用熟练后你会发现CLI比GUI效率高很多,另外,当你从鼠标转移到了键盘上后,你才会感受到,原来生活可以变得如此美好。接下来会简单列举入门准备的步骤:
Installation
请根据操作系统下载并安装Git,请参见Git Downloads。
Configuration
因为Git是分布式的,需要在本地配置Git用户名和邮箱作为一个标识。
加上--global
参数表明所有Project都使用这一配置,如果需要针对某个单独Project进行设置,可以在指定的Project中输入上述命令,但不需要--global
参数。
Repository
现在可以在本地创建一个Git仓库并进行版本管理,最最基础的常用命令如下:
GitHub + SSH Key
如果希望自己的代码上传到GitHub,可以阅读Github官方Demo教程GitHub Guides,当然也可以上传到其它代码托管平台,原理步骤基本相同。另外,如果需要添加SSH Key,可以参考Generating an SSH key。
Git初阶
除了熟练掌握上述的一些基本命令外,还不能顺畅地使用Git,还需要对更多的命令进行掌握才能达到流畅使用Git的程度,除了init,clone,status,add和commit命令外,接下来会分别介绍一些其他的常用命令及参数。
git config
除了上节提到的使用git config命令来配置user.name
和user.email
外,还有一些其他常用参数。
Git配置有三种级别:
- System:
--system
,一般很少会修改系统级配置,对应的系统配置在/etc/gitconfig
中。 - Global:
--global
,通常会修改全局配置,对应的全局配置在~/.gitconfig
或~/.config/git/config
中。 - Local:
--local
默认值,需要对某个项目单独配置时使用,对应的配置在项目目录下的.git/config
中。
git remote
在初始化新项目时,可能需要添加远程库链接,或是在现有项目中修改远程库链接,或同时指定多个源等,git remote命令相当有用,特别是add
和set-url
还是会常用到的。
当然还有更多的用法和参数,更多特殊场景用途可以参数官方的文档说明,但个人认为以上用法足够应对平时使用了。
git pull
在平常的Git使用过程中,git pull命令使用相当频繁,用于从远端仓库拉取代码,其实是包括了两个命令:git fetch和git merge。
git push
另一个常用的命令就是推送git push,用于把本地的提交推送到远端仓库。
git diff
Git中对比命令git diff用于对比提交文件或工作区文件的修改情况,通常在准备提交之前可检查一下修改,防止提交不期望的文件。
通常大家更倾向于使用IDE来对比修改,这一点倒觉得没什么问题,毕竟IDE界面上的对比有更强的视觉感,在某种程度上会减少出错的概率。
git branch
通常需要查看、创建、修改或删除一个分支时需要用到git branch,假设示例中使用的分支名为feature/card1
。
git checkout
再来介绍一下检出命令git checkout,除了对分支切换操作,还可以用于丢弃修改,常用的方式如下:
git merge
通常需要在分支间进行分支合并操作,需要用到git merge命令,比如把topic
分支merge到master
上。
当然,也可以指定一些其他参数或是合并策略等,用法非常灵活。在merge时通常会遇到合并冲突问题,如果遇到,在自己熟悉的编辑方式下解决冲突,然后运行添加命令git add -u
,最后根据提示运行git rebase --continue
即可,切记勿再commit。
git rm
删除命令git rm用于从Git的工作树和索引中删除文件。另外,还有一个类似的git mv命令,但不太常用,主要作用是改名或移动文件,只作简单了解即可。
--cached
参数相当有用的,通常的使用场景是,当某个文件已经被添加到Git管理,但后来又需要在.gitignore
中忽略。
git log
有时需要查看提交记录日志,可以使用命令git log。
git revert
Git提供了撤销某次操作的命令git revert,相当于对某次提交的回滚操作,该命令会保留之前的所有提交记录,并把撤销操作当作一次新的提交。
以上就是一些常用命令,需要自己练习进行掌握,可以花15分钟在Try Git进行简单学习,另外,Learn Git Branching提供了交互式动画教学和动手实践结合的学习方式,有兴趣可以学习下,同时,也推荐一篇《手把手教你用Git》,练习完成一系列教程后基本就可以流畅地使用Git的常用功能了。
Git进阶
除了掌握常用的命令外,还需要在实践中不断地练习,在真正遇到一些问题并解决后才能提升,踩了坑才能更深有体会,正所谓在实践中学习,在跌倒中成长。
数据恢复
只要在Git管理过的对象几乎总是可以恢复的,即使通过回退到了之前的版本,或者执行了一系列的错误操作,看似某些提交被丢失了,但可以通过查看到操作记录日志,并使用git reset命令实现回退或恢复。
除了--hard
参数外,还有另外两个参数,分别进行解释说明:
- –soft: 暂存区和工作区都不会被改变,被reset的文件会在暂存区等待新的提交,不能操作文件或路径
- –mixed: 默认选项,暂存区会被reset,但工作区不受影响,可操作文件或路径,该选项已弃用,可用
reset -- <path>
代替 - –hard: 暂存区和工作区都被reset,直接回退到指定提交,不能操作文件或路径
为了实现回退或恢复,需要查看日志,除了git log
命令外,还有git reflog命令查看Git的引用日志,即操作记录,该命令非常有用,可以检查丢失提交,或查看操作记录Hash并用于重置及撤销等操作。
暂存现场
暂存命令git stash用于保存工作区的修改现场,以便快速切换到其他工作,再在适当时机恢复之前的工作。stash@{0}
指最近一次暂存记录,stash@{1}
指上上次的暂存记录,类似于压栈的操作。
特别注意:在使用stash pop
时要小心了,万一出现误操作,Pop出来的代码与现有代码出现大量冲突,这会导致本来只需要Pull就可以自动解决所有冲突的情况变得复杂,而且代码一旦被Pop出来就没办法恢复了,就只能慢慢一行行解决冲突吧,只能呵呵达了。
部分提交
通常提交是针对一个文件,要么都提交,要么都不提交,但有时候需要在修改某个文件后,只希望暂时提交其中部分已修改内容,其他修改内容打算后续再提交。针对这种对文件进行了多次修改并希望分别提交的场景,首先需要进行部分修改暂存,然后提交,再暂存其它修改,再提交。
- 输入s表示分割该块为更小块
- 输入y表示暂存该块
- 输入n表示不暂存该块
- 输入e表示手工编辑该块
- 输入a表示暂存当前块以及当前文件的后续块
- 输入d表示退出当前文件,不处理后续块,但会转到下一个文件
- 输入q表示退出,不再处理后续块和文件
- 输入/表示搜索匹配给定Regex的块
- 输入?表示查看帮助信息
分支衍合
分支衍合命令git rebase非常实用,能够自动把分支结点衍合到upstream顶端从而保证提交树的整洁。
在拉取代码时加上
--rebase
参数总是好的,也推荐使用,即git pull -r
,这样就会把当前分支衍合到upstream的顶端,使得Network保持一条线,更加清晰直接。当在处理Merge或Patch时,会遇到冲突,当解决完成冲突后,会使用到
rebase
命令。123git rebase --continue # 继续完成之前的操作git rebase --abort # 放弃rebase过程git rebase --skip # 跳过当前rebase过程当需要把多个提交点合并成一个commit时,可以使用
rebase
命令,比如,把6a7c70c
之前的所有提交合并(注:不包括该Hash提交)。12345678910111213141516171819$ git rebase -i 6a7c70c # --interactive, 以交互的方式进行rebase操作# 通常会保留第一个为pick,其他改为squash,千万不要移除中间的任何一次提交,保存退出# Commands:# p, pick = use commit# r, reword = use commit, but edit the commit message# e, edit = use commit, but stop for amending# s, squash = use commit, but meld into previous commit# f, fixup = like "squash", but discard this commit's log message# x, exec = run command (the rest of the line) using shell# 如果出现错误提示'Could not execute editor',可以尝试配置编辑器修复此问题:$ git config --global core.editor /usr/bin/vim# Squash Last N Commits, 即压缩最近的N个提交git rebase -i HEAD~N# 与远端的保持一致,若之前已经Push了,则会撤消刚刚的Squash操作git rebase origin/master当出现了Infinity分支,或者需要简化分支的树,可以使用
rebase
命令,假设在release/v2上需要rebase到develop的6a7c70c点上。123git checkout release/v2git rebase 6a7c70cgit push -f
使用标签
使用git tag命令可以帮助建立一系列的Tags,与Branch用法相似,但相对于分支来说更轻量级,并且很适合在workshop中使用,当然也可以作为轻量级项目管理release版本的策略。
修改权限
通常在管理可执行脚本时,执行权限默认不会被Git管理,比如gradlew
在本地创建完成并且也可以运行,但在服务器上拉取代码后发现没有执行权限,因此会导致执行脚本任务失败,为了解决这一问题,需要用到git update-index命令。
补丁技巧
有时会需要在某个分支上针对某个commit打patch,然后再应用到另一个分支上,作为一种补丁的形式出现。首先介绍一下git cherry-pick命令,该命令允许从其他分支上选取某一个Commit,再应用到当前分支上。
当需要生成Patch文件时,可以用命令git diff HEAD >> xxx.patch
,然后再使用命令git apply xxx.patch
应用该Patch。
另外,可以参阅更多命令git format-patch和git apply。
回收垃圾
git gc和git count-objects命令用于回收垃圾和查看数据库占用空间的。如果有太多松散对象和大文件对象,占用了太多空间,可以尝试手动运行一些命令减少空间占用。
谁的代码
还有一个很有用的命令git blame,可以查看到某个文件的每一行修改记录,有时需要确认是谁修改了某一行代码,该命令会很有帮助。
高效别名
为了提升Git命令的操作效率,通常会配置Git别名来简化命令输入,其中一种方式是自己在~/.gitconfig
中配置,但不是首选推荐使用。
还有一种推荐使用的方式,如果你使用的Oh My Zsh+iTerm2的命令行方案,那么你可以感受到Oh My Zsh
带来的优势了,提供了git plugin并设定了统一的更加简短的别名,常用的Alias如下:
其中,★★★★★
表示强烈推荐使用的项,太多Alias会导致记忆混乱,个人觉得记住基本命令的简写即可,参数由自己显示决定,另外,还是需要掌握全称更好,毕竟不是每台电脑的配置都和你的一样,但自己使用确实会方便快捷很多。
若需再定义Alias,可以在~/.zshrc
中加入自定义的Alias,如:alias gau='git add -u'
, alias gs=gst
。
另外,补充一些在PowerShell中定义常用的相同Alias,在PowerShell安装目录下新建profile.ps1
文件,并写入以下代码:
结束语
对于Git初阶部分,都是平常自己使用的一些命令,对于Git进阶部分,除了补充一些命令外,也是自己使用Git的一些心得体会和技巧,无论怎样,只有通过自己亲身实践,不断练习才能真正掌握。以上所有都只是作为一名普通Git用户的实践方式,如果需要开发一些基于Git的应用等,那就需要了解更深层次的底层命令和原理了。
References