在平常的git操做中,git checkout——檢出,是咱們的經常使用命令。最爲經常使用的兩種情形是建立分支和切換分支。html
在下面的命令中,使用了一些簡寫,在這裏說明一下:git
git st # git status git ci # git commit git br # git branch git co # git checkout git mg # git merge git line # git log --oneline
固然,你也能夠直接在git中敲命令,將這些簡寫添加到git配置中bash
git config --global -e
而後,能夠插入下面的配置:ui
[alias] st = status co = checkout br = branch mg = merge ci = commit md = commit --amend dt = difftool mt = mergetool last = log -1 HEAD cf = config line = log --oneline latest = for-each-ref --sort=-committerdate --format='%(committerdate:short) %(refname:short) [%(committername)]' ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short type = cat-file -t dump = cat-file -p
這樣,你也就可使用這些簡寫的命令咯。下面步入正題啊。3d
(一)基礎——千里之行,始於切糕(checkout)指針
先熟悉下經常使用操做,建立分支和切換分支,也能夠稱爲檢出分支。orm
首先咱們新建一個倉庫gitTest,而後新建文件a,爲何要用a命名呢,這裏是故意爲之,後面爲你們揭曉分支。呵呵。或許下面的介紹會有些枯燥乏味,由於您已經對這些命令爛熟於胸,並且運用得至關熟練,那麼您能夠直接跳過這一步。htm
在master分支上,作一次提交c1,而後如今新建一個分支a,並切換到a分支。blog
這個操做主要會用到兩個命令:ci
建立新分支:git branch branchName
切換到新分支:git checkout branchName
而後,上面兩個命令也能夠合成爲一個命令:
git checkout -b branchName
(二)真相——HEAD是checkout的靈魂
其實,咱們在切換分支,和新建分支的時候,有沒有想過,這些操做操做背後的工做原理是怎樣的呢?最大的功臣就是.git目錄下的HEAD引用,她宛如一個芭蕾舞者,從一個分支飄逸的跳到另外一個分支,雖無聲無息,卻精準無比。
在咱們身處master分支的時候,您必定很好奇,當前的HEAD的內容是什麼?不妨來看看吧。
咱們看到c1的提交hash值和HEAD對應分支master的當前hash值是同樣的。也就是說,HEAD指向的是當前分支名master,而master又對應了當前的最新的一次提交ID.
好,那麼咱們再作一次提交,看看master對應的hash值有無變化。
從上圖,咱們能夠不難看出,HEAD對應的ref沒有變化,仍是master,可是master對應的commit ID卻變成了c2對應的commit ID,即更新爲最後一次提交的ID咯。
如今,提交一次的原理,咱們已然瞭解,那麼切換分支的時候呢??
如今咱們身處master分支,而後咱們切換到a分支,看看會發生什麼樣的狀況吧。
從上圖分析,在master分支上的時候,HEAD指向的是master,對應的是c2的commit ID。而切換到a分支的時候,HEAD也相應的指向了a,同時a對應的是a分支上的最新commit ID。所以,咱們能夠得出結論,在切換分支的時候,HEAD也會相應的指向對應的分支引用。
可是,使用checkout命令的時候,並非每次都會改變HEAD指針的指向哦。在什麼狀況下HEAD一直堅決不移的擁護者他的女神呢?可謂衣帶漸寬終不悔,長使英雄淚滿襟啊!讓咱們接着往下看。
(三)進階——HEAD懂不懂,看你怎麼用
checkout命令用法以下:
1. git checkout [-q] [<commit>] [--] <paths> ...
2. git checkout [<branch>]
3. git checkout [-m] [ [-b | -- orphan ] <new_branch>] [start_point]
用法2比用法1的區別在於,用法1包含了路徑。爲了不路徑和引用(或提交ID)同名而發生衝突,能夠在<paths>前用兩個連續的連字符做爲分隔。用法1的<commit>是可選項,若是省略,則至關於從暫存區進行檢出。
來看個例子:
情景1,省略掉<commit>
如今咱們處於master分支下,而後咱們修改了文件a,輸入「c3」文本到a中,這時候,暫存區中的內容是沒有"c3"的,經過git diff能夠比較。如今咱們從當前分支暫存區中檢出文件a。那麼咱們能夠直接使用git checkout a。
這時候,提示檢出失敗,git覺得咱們想檢出倉庫a。還記得爲何在第一步中,咱們曾新建的文件a嗎?這裏終於派上用場了,因爲倉庫中還存在分支a,同時當前分支中又存在文件a,因而git傻傻分不清楚了。這時候怎麼辦?有兩個辦法,第一,咱們在命名分支的時候要注意語義性,分支名要具備必定的意義,不能使用簡單的a,b,c來命名,這樣很容易致使分支名和文件名重複;第二,參照用法1,使用兩個連字符來分隔。在目前的情形中,咱們使用第二種方法吧。
這時候,發現工做區的內容被暫存區的內容覆蓋,"c3"文本也沒有了,固然HEAD指針也沒有什麼變化,一切又恢復了平靜。
再看一個例子:
情景2,不省略<commit>
在不省略<commit>的時候,<commit>既能夠是某一個具體的commit hash值,也能夠是某個分支名稱,tag名稱。不論分支也好,tag也好,它們本質上對應的都是一個commit hash值。
在檢出a分支下的a文件的時候,最好把兩個連字符加上,否則git也會沒法區分。整個過程當中,HEAD頭指針沒有發生改動。
總結:第1種用法(包含<paths>的用法)不會改變HEAD頭指針,主要使用於指定版本的文件覆蓋工做區中對應的文件。若是省略<commit>,則會用暫存區的文件覆蓋工做區中的文件,不然用指定提交中的文件覆蓋暫存區和工做區中的對應文件。
接下來,咱們看看用法2,在第一部分中,咱們知道切換分支,會改變HEAD的指向,那麼若是咱們是檢出某個commit會怎樣呢?同檢出分支同樣,會用該commit下的內容覆蓋當前分支工做區和暫存區的內容,請看例子。
目前咱們處於master分支上,且已經有了兩次提交,分別是c1和c2,而後咱們修改a,給a文件添加內容"c3",並add到暫存區,隨即便用checkout到c1的commit 上。注意,剛開始checkout的時候,git不會容許你直接切換,由於你修改了暫存區的內容, 它會提醒你提交後再切換,這時候,你可使用-f 強行切換。再查看狀態的時候,git提示咱們已經不在任何分支上,HEAD指針也是指向具體的c1的commit值,進入了「分離頭指針」狀態。這個狀態下,要回到master上面,只須要git checkout master便可,也能夠在這個狀態上新建分支。
若是,checkou後面不跟任何參數,則就是對工做區進行檢查,請看例子。
咱們身處master分支上,而且沒有任何改動,這時候git checkout沒有任何輸出。而後,咱們給a文件添加內容「c3」,而後再git checkout一下,git就會提示a文件有修改,是否是很簡單?
總結:對於第2種用法,不是檢出某個具體文件的的時候,即不指定<paths>的時候,單純的檢出某個commit或分支,是會改變HEAD頭指針的。並且只有當HEAD切換到某個分支的時候才能夠對提交進行跟蹤,不然就會進入「分離頭指針」的狀態。若是省略用法2後面的<branch>,則默認對工做區進行狀態檢查。
(四)熟悉的checkout,陌生的用法,媽媽不再用擔憂個人checkout啦!
1. git branch <branch> <start point>
以某個commit建立新分支。 在一般狀況下,咱們都會在當前分支的基礎上,建立新分支。好比git branch new_branch
也許你不知道,咱們還能夠基於當前分支的某一次commit來建立分支。請看!
從上圖可見,咱們想基於master分支的c1 提交ID建立新分支new_branch,建立成功後,切換到new_branch,查看log,只有c1,耶~~成功啦!
固然,也可使用git checkout -b <new_branch> <start point>這個經常使用的命令。
2. git checkout --datch <branch>
切換到分支的遊離狀態,默認以該分支下的最後一次提交ID,請看下面的例子。
當前分支爲a,而後使用git checkout --detach master,那麼HEAD就會切換到master的最後一次commit值的狀態下!
3. git checkout -B <branch>
這個命令,能夠強制建立新的分支,爲何加-B呢?若是當前倉庫中,已經存在一個跟你新建分支同名的分支,那麼使用普通的git checkout -b <branch>這個命令,是會報錯的,且同名分支沒法建立。若是使用-B參數,那麼就能夠強制建立新的分支,並會覆蓋掉原來的分支。請看具體操做。
當前分支爲master,且倉庫中已經存在分支a,咱們先用git checkout -b a來建立a分支,必然會失敗的,並提示咱們倉庫中已經有了一個a分支咯,彷彿在說「hi,哥們,你已經有了一個老婆了,一夫一妻制你的不懂?你覺得這裏是印度啊?」。隨後,咱們使用git checkout -B a,耶~~,it works!
4. git checkout --orphan <branch>
是的,假如你的某個分支上,積累了無數次的提交,你也懶得去打理,打印出的log也讓你無力吐槽,那麼這個命令將是你的神器,它會基於當前所在分支新建一個赤裸裸的分支,沒有任何的提交歷史,可是當前分支的內容一一俱全。新建的分支,嚴格意義上說,還不是一個分支,由於HEAD指向的引用中沒有commit值,只有在進行一次提交後,它纔算得上真正的分支。還等什麼呢?趕忙試試!
好了,如今咱們終於找到組織了!
5. git checkout --merge <branch>
這個命令適用於在切換分支的時候,將當前分支修改的內容一塊兒打包帶走,同步到切換的分支下。
有兩個須要注意的問題。
第一,若是當前分支和切換分支間的內容不一樣的話,容易形成衝突。
第二,切換到新分支後,當前分支修改過的內容就丟失了。
因此這個命令,慎用!
6. git checkout -p <branch>
這個命令能夠用來打補丁。這個命令主要用來比較兩個分支間的差別內容,並提供交互式的界面來選擇進一步的操做。這個命令不只能夠比較兩個分支間的差別,還能夠比較單個文件的差別哦!
結束語:至此,關於git checkout命令暫告一段落,對於checkout命令,你也有所熟悉了吧。固然,git checkout還有一些其它用法,本文並無講到,你能夠在git bash或終端中使用git checkout --help去進一步瞭解!
轉載:http://www.cnblogs.com/hutaoer/archive/2013/05/07/git_checkout.html?utm_source=tuicool&utm_medium=referral