Git checkout 的三种用法
从英文单词 checkout 说起
Checkout 的本意是“结账”,一般翻译成“检出、签出”。
“结账”表示住酒店或者逛超市的过程结束了,需要离开酒店或者离开超市,前往一个新的地方。
与之类似,git checkout
命令也是离开一个分支、提交、文件,前往到另一个分支、提交、文件。
离开,再前往另一个,这个过程可以称之为切换。
Git checkout 命令的功能和用法
在此基础上,理解和记忆 git checkout
命令的功能,就变得比较容易了。
Git checkout
命令有三种主要功能:
- 切换分支,离开当前分支,前往另一分支,也可以用来新建分支。
- 切换提交,离开当前分支,以“分离 HEAD”(detached HEAD)前往另一提交。
- 撤销工作区中一个或多个文件的修改。
撤销工作区中的修改,可以理解成:离开工作区中的某个文件,前往它的上一个版本,也就是用暂存区(或版本库)中的同名文件覆盖工作区的这个文件。
理解了 git checkout
命令的三种功能的实质都是切换,再去记忆它的用法就很容易了,更不必去死记硬背 Git 2.23 新引入的 git switch
和 git restore
命令,平白增加记忆量。
Git checkout 有三种主要用法:
git checkout [-b] <branch-name>
:切换到另一个分支上工作,如果有-b
参数,表示新建一个分支并切换到这个分支上工作。。git checkout <commit-id>
:通过分离 HEAD(detached HEAD) 的方式切换到另一个提交上工作。git checkout -- <filename>
:撤销工作区中一个或多个文件的修改(可以把撤销修改理解成同一个文件切换到未修改的状态)。如果已经将工作区中的文件保存到暂存区(索引、Stage),就用暂存区中的内容覆盖工作区中的文件。如果暂存区中的文件已经提交到版本库,也就是说暂存区里没有这个文件,就用版本库中的内容覆盖工作区中的文件。
注意:对于在工作区中新建并且尚未 git add
(或 git commit
)过的文件,git checkout -- <文件名>
无效。
以上三种用法的共同点都是:从表面上看,会修改工作区中的文件;实质上是移动指针,指向版本库中不同的提交。
- 切换到另一个分支、提交,就会用版本库中的文件覆盖工作区中的文件。
- 撤销文件的修改,实质上是用版本库中的文件覆盖工作区中的文件。
## 切换提交与分离 HEAD
既然每一次提交都代表一个版本,那么我们可以用 git checkout
在不同的提交之间切换,具体用法是 git checkout <commit-id>
,就像时光机一样,在不同的时间点之间飞行。
如果要切换回 master 分支上最新的提交(此处假设只有一个分支 master),需要执行 git checkout master
。
如果要切换到其他提交,可以用 git reflog
拉出每一次提交的 commit-id,然后用 git checkout <commit-id>
切换到对应的提交。
前文说道,它是以“分离 HEAD”的方式切换到另一提交的,那么,分离 HEAD 是什么意思呢?
原来,按照 Git 设计的底层逻辑,HEAD 是用来引用最新快照的指针。HEAD 作为一个指针是指向当前分支的,而当前分支也是一个指针,指向最新的提交。
所谓分离 HEAD 就是让 HEAD 指向了一个未命名的分支。
在这个未命名的分支上,可以对工作区中的文件作任意修改,或者随意提交,但是不会保存。此处不会保存的意思是说,只要切换到其他的分支,那么在这个未命名的分支上做的任何修改或提交都会被丢弃。
如果想要保存修改怎么办?需要创建一个新分支,可以执行以下两条命令其中之一:
git checkout -b <分支名>
git switch -c <分支名>
如果只是为了回顾一下以前的提交,那么不需要创建分支。
廖雪峰老师的 Git 教程把切换提交比喻成时光机,不过他用的命令是 git reset --hard <commit-id>
。而我倾向于使用 git checkout <commit-id>
。
图片版权
题图:https://www.deviantart.com/black-pixel/art/Git-Wallpaper-Clean-357130508
头图:Image by Michael Pointner from Pixabay