
本文是對(duì)
git checkout命令的一次測(cè)試。它將會(huì)覆蓋使用舉例以及不太常見的邊緣案例。在Git術(shù)語中,“checkout”的意思就是對(duì)于一種實(shí)體的不同版本之間進(jìn)行切換的操作。git checkout命令可以用于三種不同的實(shí)體:文件,commit,以及分支。作為對(duì)于checkout 含義的補(bǔ)充,短語“checking out”通常意味著執(zhí)行git checkout 命令的這一行為。但對(duì)于本文檔的大多數(shù)讀者來說,checkout操作將主要使用于分支。
checkout分支類似于檢出一個(gè)分支中的某次舊的commit;然而,新的變更會(huì)被存儲(chǔ)在項(xiàng)目的歷史中,這也就意味著這并不是一個(gè)只讀的操作。
檢出分支
git checkout命令可以切換通過git branch命令創(chuàng)建的分支。checkout一個(gè)分支,會(huì)更新當(dāng)前的工作空間中的文件,使其與檢出分支的commit版本狀況保持一致。這之后工作區(qū)中的所有變更都會(huì)被記錄在checkout出來的那個(gè)分支上。這一操作可以認(rèn)為是在挑選你希望修改的工作分支。
相比于SVN的工作流,為每一個(gè)新功能的開發(fā)都建立一個(gè)獨(dú)立的分支是一個(gè)巨大的進(jìn)步。這一特性足以在不用懼怕破壞現(xiàn)有功能的前提下隨意實(shí)驗(yàn)新的功能開發(fā),還可以讓同一個(gè)開發(fā)者并行展開多個(gè)互不相關(guān)的新功能開發(fā)。甚至,這種簡(jiǎn)單又輕松的分支模型,還促進(jìn)了不少協(xié)作的工作流程的出現(xiàn)。
git checkout命令有時(shí)候會(huì)跟git clone命令相混淆。兩個(gè)命令中最為顯著的差別在于,git clone用于從遠(yuǎn)程倉(cāng)庫(kù)獲取代碼,而git checkout則用來在本地系統(tǒng)中業(yè)已存在的代碼庫(kù)中切換不同的版本。
使用:現(xiàn)有的分支
設(shè)想你正在工作的倉(cāng)庫(kù)中含有一些現(xiàn)有分支,那么你可以使用git checkout命令在這些分支之間進(jìn)行切換。為了找出哪些分支是可用的,以及當(dāng)前我們正在使用哪個(gè)分支,可以執(zhí)行git branch命令
$> git branch
main
another_branch
feature_inprogress_branch
$> git checkout feature_inprogress_branch
上面的例子演示了如何使用git branch命令來查看所有可用分支,以及如何切換到一個(gè)指定的分支,在此例中,即切換到feature_inprogress_branch分支上去。
創(chuàng)建新分支
git checkout常與git branch協(xié)作。git branch命令可以用于創(chuàng)建一個(gè)新的分支。當(dāng)你希望開始某個(gè)新功能的開發(fā),可以使用git branch new_branch來創(chuàng)建新的分支。一旦創(chuàng)建完成,就可以繼續(xù)使用git checkout new_branch來切換到這個(gè)新創(chuàng)建好的分支。此外,git checkout命令還接受一個(gè) -b 參數(shù),作為創(chuàng)建分支并立刻切換到新分支這一系列操作的快捷方式。在創(chuàng)建了一堆新分支之后,則可以繼續(xù)使用git checkout命令在這些分支之間進(jìn)行切換,以便并行地對(duì)多個(gè)新功能展開同步開發(fā)工作。
git checkout -b <new-branch>
以上命令同時(shí)創(chuàng)建并checkout到 <new-branch>上。-b選項(xiàng)作為一個(gè)標(biāo)記告訴git先運(yùn)行git branch命令然后再運(yùn)行git checkout <new-branch>命令。
git checkout -b <new-branch> <existing-branch>
默認(rèn)的git checkout -b命令會(huì)從當(dāng)前所在的HEAD指針?biāo)傅姆种砼缮鲂陆ǖ姆种?。?code>git checkout命令仍然可以接受一個(gè)可選的分支名作為參數(shù)。在上面的例子中,<existing-branch> 作為這個(gè)參數(shù)傳遞給git checkout命令,這一命令意味著從指定的existing-branch分支派生創(chuàng)建了一個(gè)名為new-branch的新分支。
切換分支
切換分支命令是一個(gè)非常直白的操作。執(zhí)行下面命令會(huì)讓HEAD指針指向<branchname>分支的頂端。
git checkout <branchname>
Git會(huì)在reflog中記錄checkout操作的歷史。你可以執(zhí)行git reflog命令來查看這一歷史記錄。
checkout一個(gè)遠(yuǎn)程分支
與他人協(xié)作的情況下則一定會(huì)涉及到使用遠(yuǎn)程倉(cāng)庫(kù)。這些遠(yuǎn)程倉(cāng)庫(kù)可能是托管在一個(gè)共享節(jié)點(diǎn)上,也可能就是其他同事的一個(gè)本地倉(cāng)庫(kù)。每個(gè)遠(yuǎn)程倉(cāng)庫(kù)都有自己的分支集合。為了能夠checkout出某一個(gè)遠(yuǎn)程倉(cāng)庫(kù)的分支,我們需要先fetch那個(gè)倉(cāng)庫(kù)的內(nèi)容。
git fetch --all
之后在較新版本的Git中,你就可以像checkout本地分支一樣checkout出這個(gè)遠(yuǎn)程分支了。
git checkout <remotebranch>
對(duì)于比較老的Git版本,則需要先基于remote中的指定遠(yuǎn)程分支創(chuàng)建一個(gè)新分支。
git checkout -b <remotebranch> origin/<remotebranch>
此外,你還可以checkout一個(gè)本地分支,然后將其硬重置為遠(yuǎn)程分支的最新commit。
git checkout -b <branchname>
git reset --hard origin/<branchname>
游離狀態(tài)的HEADS
在我們已經(jīng)見識(shí)到git checkout命令對(duì)于分支的三大主要操作之后,現(xiàn)在該到了討論一下“游離狀態(tài)的HEAD”的問題了。再次明確一下,HEAD是Git中用來引用當(dāng)前快照的指針。在Git內(nèi)部,git checkout命令只是簡(jiǎn)單地將HEAD指針更新為指向特定分支或者commit。當(dāng)它指向一個(gè)分支時(shí),沒什么問題,但是當(dāng)你checkout了一個(gè)特定的commit,就會(huì)將HEAD指針變成一個(gè)游離的指針狀態(tài)。
當(dāng)進(jìn)入這種游離狀態(tài)時(shí),Git會(huì)警告你當(dāng)前處于游離狀態(tài),你所做的任何更改也都游離于你整個(gè)項(xiàng)目的開發(fā)流程。如果你執(zhí)意要在游離狀態(tài)開展新的修改,這些修改將不會(huì)被允許再合并回任何分支。然后當(dāng)你沒有辦法只能切換到其他分支時(shí),這部分修改也無法被帶回到新的分支:

重點(diǎn)在于,開發(fā)工作應(yīng)該始終發(fā)生在一個(gè)分支上——而不是一個(gè)游離狀態(tài)的
HEAD上。謹(jǐn)記這一原則可以保證你的變更提交永遠(yuǎn)都能找到。當(dāng)然,如果你只是為了去看看某一個(gè)過去的提交,則無所謂是否處于游離狀態(tài)。
總結(jié)
本文重點(diǎn)是關(guān)于使用git checkout命令進(jìn)行分支的切換??偠灾槍?duì)分支使用git checkout命令,會(huì)切換當(dāng)前的HEAD指針指向。它還可用于創(chuàng)建分支,切換分支,checkout遠(yuǎn)程分支。git checkout命令對(duì)于Git項(xiàng)目的操作來說是至關(guān)重要的??梢哉J(rèn)為它與git merge命令是一體兩面。git checkout命令和git merge命令結(jié)合在一起使用才使得一系列復(fù)雜而又精妙的git 工作流程成為可能。