在软件开发过程中,Git是一种服务于项目版本管理的重要工具,世界上各个开源项目仓库诸如Github均使用git进行代码仓库的操作。
一般地,有两种途径来使用Git工具,一种是第三方开发的交互式界面软件,另一种则是直接使用命令行指令。使用Git交互式界面软件来操作代码仓库,好处是操作简单直观,学习成本低。而本文的主旨在于从代码层面上了解Git工具的操作原理,做到知其然知且其所以然,遇到相关问题能够找到正确的方法进行解决,故仅对命令行进行使用说明详述。
使用前须知
“The three trees” - “三棵树”
在使用Git指令之前,各位小伙伴须将一概念熟记于心,这个概念被称作“The three trees”。下面我们用一张图来进行理解:
图1 The three trees-
Working Directory - 工作目录
即项目所在文件夹,也就是你的项目根目录。 -
Staged Snapshot - 临时快照
即当你对Working Directory中的文件进行了任何CRUD操作,并且对这些操作执行了git add
命令,此时这些文件便进入到了Staged状态。进入到Staged状态的文件,即可以进行commit操作进入到Commit History,也可以进行reset操作回退到Unstaged状态。下面用两张图来进行理解:
上图中,对Working Directory中的www文件进行了修改,执行git status可以看到,www进入了git的检测列表,状态为Unstaged。此时,我们再执行git add .
,得到下图结果,此时,www进入到了Staged Snapshot中:
- Commit History
即已提交历史,对项目的任何修改已被提交到本地仓库中,该记录已进入到提交历史中,可通过git log
进行查询。下图为提交后结果:
注意:完成commit操作不等同于push到远程分支,并不会对远程分支造成任何影响,同时
pull
、push
以及分支概念不在本文的研究范围中,故不做赘述。
Scope - 作用范围
作用范围也是Git使用中必须要掌握的一个概念,所谓作用范围,是指Git指令所起作用的两种对象(层级),分别是File-level和Commit-level。就之前的图2为例,当www文件被修改之后,此时可对该修改文件进行2种操作,一种是git add
使其进入到Staged Snapshot中,另一种则是git checkout
令其还原到修改前的状态。
- File-level
文件层级为Git指令对单个或者多个文件(指令中反映为文件路径)进行的操作,git checkout
、git reset
均可作用于该层级。
注意:
git revert
没有File Scope操作。
- Commit-level
提交层级为Git指令对Commit History中的单条或多条commit进行的操作,git checkout
、git reset
、git revert
均可作用于该层级。下面附上三种指令对应Scope的表格:
Git指令 | 作用范围 | 常用场景 |
---|---|---|
git checkout | Commit-level | 1. 分支间切换 2. 切换到同一分支下的指定commit进行代码浏览(分离状态,下文会进一步阐述说明) |
git checkout | File-level | 还原对某个或多个文件的修改(该操作不可逆,慎用) |
git reset | Commit-level | 还原某一分支上已提交的某条或多条commits(适用于个人分支,该操作不可逆,慎用) |
git reset | File-level | 将Staged状态下的某个或多个文件,还原到Unstaged状态 |
git revert | Commit-level | 撤销某分支上的已提交内容(适用于公共分支) |
git revert | File-level | 无文件层级操作 |
git checkout
分支切换
git checkout
指令用于更新当前项目所处状态,若指令所指定的值为分支名,则切换到该指定分支。例如,我们打算将当前所处master分支,切换到hotfix分支上,执行如下代码:
git checkout hotfix
此时,若当前分支上的修改可能对目标分支上的文件造成覆写,则Git会强制中断此次操作,并提示哪些文件可能导致覆写,提出操作建议。当你完成修改后,即能够进行成功切换,git checkout
指令的执行机制如下图所示,其中,HEAD可以理解为头指针,用于指向当前项目代码所处的分支,以及commit history位置:
切换前,HEAD指向Master分支的最近一次代码提交位置;切换后,HEAD指向Hotfix分支的最近一次代码提交位置。
指定commit history位置切换
git checkout
也可以用于切换到某一分支上的指定commit位置,当指令值为commit id时,则能够将HEAD指向该次commit,例如,我们想要将代码回溯到上上一次commit位置进行快速浏览时,则可以运行以下指令:
git checkout HEAD~2
为了方便理解,下图表示了此次指令的执行机制:
图6 git checkout <commit>可以看到,执行完毕后,HEAD已经指向了上上一次commit的位置。git checkout
的这项特性使得用户能够快速地切换到目标commit对代码进行查阅,并且不会对当前分支造成任何影响,此时HEAD指向的代码位置不属于任何一个分支的任何一次commit,这样的状态叫做'detached HEAD' state,执行结果见下图所示:
需要注意的是,处于detached HEAD状态的代码,在你切换到任何分支后,都会丢失得不到保存,所以,如果你想要在该commit上进行修改并提交,请务必在修改前执行git checkout -b <new-branch-name>
,这样,你可以得到一个同该commit代码一模一样的新分支,并进行任何能够得到记录的操作。
还原Unstaged状态的文件
git checkout
还能够作用于Unstaged状态下的文件,执行后,该文件的任何修改都会还原到此次修改前的状态,这种场景常见于当你进行了某些实验性质的修改或者因某些原因需要放弃此次修改时。执行指令如下:
git checkout -- <single file path> // 还原单个文件
git checkout -- . // 还原所有此次修改文件
本章完。
下一章节将主要介绍git reset指令。
文中部分图片源于www.atlassian.com。
参考文献
https://git-scm.com/docs/git-checkout
https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting
网友评论