1. 程式人生 > >git merge,rebase和*(no branch)

git merge,rebase和*(no branch)

git merge,rebase和*(no branch)

2014年04月18日 14:24:15 乜都得 閱讀數:9740 標籤: gitmergerebaseno branch 更多

個人分類: 版本控制

        上一篇:http://blog.csdn.net/xiaoputao0903/article/details/23933589,說了git的分支,相關的用法沒說到但是隻要google就能搜出一大片,這裡還有幾個細節要注意一下,就是merge合併和rebase合併的區別,以及*(no branch)的處理。

1.merge

        在上篇介紹分支的時候有簡單的說了一下分支的建立和合並,當時合併就是寫的merge,這是根據兩個不同分支的最後一次提交的commit物件c5,c7和兩個分支的交叉點的commit物件c3進行一次簡單的三方合併,最終得到一個新的commit來作為最終的提交commit物件c8,指標指向c8,而且c4,c5,c6,c7是存在於本地倉庫的歷史版本,我們可以通過日誌檢視找到這兩個commit,同樣也可以恢復到這兩個版本。也就是下面這個圖:

        上圖是將test分支合併到master分支,然後我們來實現一次,假如現在已經到了c3,我新建一個分支test,然後先用master分支修改我的test.txt檔案並提交重複兩次,得到c4和c5,然後再切換到test分支同樣對test.txt修改並提交兩次,得到c6和c7,然後切換到master分支執行合併操作,這時會提示有衝突,最後我們解決衝突了再提交:

衝突:

日誌:

2.rebase

        rebase稱為衍合,這是個什麼概念呢,如下圖,當我們把test衍合到master的時候,是將c5,和c6中發生的變化打成補丁然後再c8的基礎上做修改的,如果這個時候遇到衝突,就必須要我們自己決絕好衝突之後,新增到暫存區然後再繼續合併,c5的變化補丁在c8上發生變化之後得到c5'這個commit物件,而c6的變化補丁再在c5'上修改得到c6',然後指標指向c6',這個過程我們稱之為衍合,而且這個過程都是在一個*(no branch)分支上做的,這個後面會說到。而且有一個要注意的地方,如果git執行git gc或者我們手動執行git gc,那麼c5和c6就不再存在於我們的本地倉庫,我們就再也找不回這兩個commit了,這個過程就是一個線性的過程,在test執行完之後,再在test的基礎上執行master的操作。以上就是rebase和merge的區別所在。

        和merge一樣,我們實際來做一次,假設現在我們已經在c4了,這時候建立test分支,所有修改操作和merge一樣,然後我們用rebase這種方式來把test衍合到master上:

衝突:

日誌:

3.*(no branch)

        在執行命令git branch檢視分支的時候,如果出現*(no branch),則表示不在任何分支上進行工作。出現這種情況我也是在幾次不經意之間,用git checkou回溯版本的時候,用git pull或者merge和rebase的時候會出現*(no branch)。目前我在rebase的時候都是在*(no branch)上進行的,當衍合完成後自動切到master上,我覺得這是個正常現象,但是其他幾種方式就不正常了,具體原因我也不是很清楚。

        由於*(no branch)表示不在任何分支上進行,而有時我們不知道自己是在*(no branch)上進行操作的,而且可能我們已經進行很久的開發工作了,已經提交好幾個版本的程式碼了,突然執行git branch發現在*(no branch)上,是不是一件很恐怖的事啊。

        當然經過提交的版本資料都會以快照的方式被記錄在commit物件存在.git目錄的objects子目錄裡,那麼當我們發現是在*(no branch)時應該怎麼解決呢。有兩種情況。

        第一種情況是我們還沒離開*(no branch),這個時候,我們可以執行git checkout -b mybranch命令,這個時候會建立新分支mybranch,並將*(no branch)裡面的資料都checkout到mybranch分支上,然後我們再在mybranch上開發,最終合併到master上。

        第二種情況就不樂觀了,我們已經離開*(no branch)了,然後發現用git log都找不到之前的提交了,當然了,在*(no branch)上提交的,在別的分支上怎麼找的到在它上面提交的資料呢。不過也許還有救,如果git還沒有執行git gc,那麼我們可以通過執行git reflog找到在*(no branch)上提交的資料,然後根據找到的commit的id來恢復該資料,這也是最後唯一的希望了,如果git已經執行了git gc或者你手賤自己執行了git gc,那麼就真的不能在一起愉快的玩耍了。

        所以在執行過git checkout恢復過以前的資料或者是做過合併分支的操作,那麼不要吝嗇你們的git branch,敲這個命令又不要錢,卻能讓你之後的提交高枕無憂。

4.總結

        merge的合併是三方合併,而且歷史版本都在本地方庫中,但是卻比較繁瑣,而且開發的過程是個網狀結構,如果建立的分支比較多,進行的merge也比較多,那麼就算我們在紙上畫它的提交歷史都會畫的手疼,但是rebase就不一樣,它是根據另外一個分支的修改內容進行打補丁然後在前一個分支的最後提交上進行修改,而且將另外一個分支的提交歷史刪除,這樣就是一個線性的過程,很清晰。所以在推送到遠端倉庫之前儘量多用rebase來衍合分支,但是如果將一個commit推送到遠端倉庫之後,就不要再對它進行衍合操作了,因為這樣的話,它很可能在你的某次衍合過程中被刪除,那麼再推送到遠端倉庫就會造成很大的損失。切記,rebase雖好可不要貪杯。