基本功能
checkout 主要作用有兩個(gè):切換分支和重置文件。
切換分支
切換分支時(shí),會(huì)使用新分支指向的結(jié)點(diǎn)更新暫存區(qū)與工作目錄。
正常切換
可以使用 git checkout <branch> 切換分支。其中 branch 表示要切換到的分支名。
我們也可以使用 git reset <branch>。但它與 checkout 時(shí)的含義完全不同:reset 不會(huì)更改分支,只是修改當(dāng)前分支指向的結(jié)點(diǎn);而 checkout 會(huì)更新分支,但舊分支指向的結(jié)點(diǎn)不會(huì)變化。下圖展示了 git reset master 與 git checkout master 的區(qū)別:

從上圖可以發(fā)現(xiàn):reset 之后,develop 分支指向的結(jié)點(diǎn)發(fā)生了變化,但 HEAD (HEAD 表示當(dāng)前的分支)沒(méi)有變;而 checkout 后,develop 指向的結(jié)點(diǎn)沒(méi)變,但 HEAD 指向發(fā)生了變化。
匿名分支
checkout 后不但可以跟分支名,還可以跟某個(gè)提交結(jié)點(diǎn)的 SHA-1 值,此時(shí)相當(dāng)于在指定的提交結(jié)點(diǎn)處建立一個(gè)匿名分支,然后將 HEAD 指向該分支。
之所以叫匿名分支,是因?yàn)樵?refs/heads 目錄中并沒(méi)有新建一個(gè)分支文件,只是通過(guò) .git/HEAD 文件保存了該結(jié)點(diǎn)的 SHA-1 值。
要注意:當(dāng)從匿名分支中切出時(shí),匿名分支中的所有提交結(jié)點(diǎn)將丟失,因?yàn)闆](méi)有指針指向這些結(jié)點(diǎn),也無(wú)法通過(guò)別的指針回溯到這些結(jié)點(diǎn)。
$ git checkout c9186325368de33dcfed7b4997eaab6a42f6e43b
Note: checking out 'c9186325368de33dcfed7b4997eaab6a42f6e43b'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at c918632... fda
$ git branch
* (HEAD detached at c918632)
dev
master
$ cat .git/HEAD
c9186325368de33dcfed7b4997eaab6a42f6e43b
$ ls .git/refs/heads/
dev master
在 checkout 的第一段提示中說(shuō):you can discard any commits you make in this
state without impacting any branches by performing another checkout(當(dāng)你從當(dāng)前分支中切走時(shí),本分支所有的提交都將丟失)。
重置文件
checkout 執(zhí)行重置文件工作時(shí),并不會(huì)切換分支 ,即不會(huì)修改 HEAD 指向。
重置文件時(shí),checkout 可以指定文件路徑,此時(shí)類(lèi)似于 git reset --hard -- paths,但 git 不允許后者的寫(xiě)法。
根據(jù)是否指定有提交結(jié)點(diǎn), checkout 重置文件會(huì)有兩種不同的效果:
-
指定有提交結(jié)點(diǎn),會(huì)使用該結(jié)點(diǎn)對(duì)應(yīng)的快照重置暫存區(qū)與工作目錄。
$ cat a.txt 這是用于指定提交結(jié)點(diǎn)的 checkout 重置恢復(fù) checkout -- a.txt test checkout this is update after addfd000000addfdasfas $ vim a.txt $ cat a.txt 這是后來(lái)修改的 這是用于指定提交結(jié)點(diǎn)的 checkout 重置恢復(fù) checkout -- a.txt test checkout this is update after addfd000000addfdasfas $ git checkout HEAD -- a.txt $ cat a.txt 這是用于指定提交結(jié)點(diǎn)的 checkout 重置恢復(fù) checkout -- a.txt test checkout this is update after addfd000000addfdasfas $ git status On branch dev nothing to commit, working directory clean上述命令分為四步:
顯示上次提交后 a.txt 的內(nèi)容。
修改 a.txt,只是在文件的第一行中添加了 "這是后來(lái)修改的"。
使用 checkout HEAD 重置 a.txt??梢园l(fā)現(xiàn)重置后 a.txt 恢復(fù)到修改之前的樣子。
最后使用 git status 查看狀態(tài),可以發(fā)現(xiàn) dev 分支是干凈的,即沒(méi)有需要暫存的,也沒(méi)有需要提交的 —— 這表示本地倉(cāng)庫(kù)、暫存區(qū)、工作目錄三者是一致的。
可以將重置時(shí)的 HEAD 替換成任意提交結(jié)點(diǎn)的 SHA-1 值。
-
未指定提交結(jié)點(diǎn),會(huì)使用暫存區(qū)中的內(nèi)容重置工作目錄。
$ vim a.txt $ git status On branch dev Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: a.txt no changes added to commit (use "git add" and/or "git commit -a") $ git checkout -- a.txt $ git status On branch dev nothing to commit, working directory clean可以看出,使用 git checkout -- a.txt 后,a.txt 并沒(méi)有出現(xiàn)在待暫存列表中。這是因?yàn)?checkout 使用暫存區(qū)中的文件重置了工作目錄中的 a.txt ,暫存區(qū)與工作目錄中的 a.txt 完全一樣,不需要再次暫存。
沖突文件
--conflict
通過(guò)指定 --conflict 選項(xiàng)的值,用于指定檢出沖突文件的內(nèi)容。
下表列出了 conflict 選項(xiàng)常用的值
| 屬性值 | 含義 |
|---|---|
| merge | 列出本分支,被合并分支的沖突內(nèi)容。默認(rèn)值 |
| diff3 | 在 merge 基礎(chǔ)上再列出最近公共祖先結(jié)點(diǎn)的內(nèi)容 |
--diff3 時(shí)的效果:
$ git checkout --conflict=diff3 a.txt
hufeng@hufengdeMacBook-Pro:~/Desktop/demo$ cat a.txt
<<<<<<< ours
from maste2
||||||| base
from maste
=======
from dev
>>>>>>> theirs
可以看出,與普通沖突文件的內(nèi)容相比,多了 ||||||| base 行,而該行就是公共祖先結(jié)點(diǎn)在沖突處的內(nèi)容。
--ours 與 --theirs
與 --conflict 類(lèi)似,ours 與 theirs 也是作用于沖突時(shí)沖突文件的內(nèi)容的選項(xiàng)。
--ours 是保留本分支的內(nèi)容,拋棄被合并分支;
--theirs 保留被合并分支內(nèi)容,拋棄本分支內(nèi)容。