1. 程式人生 > >關於git merge,rebase合並的差別,以及*(no branch)的處理。

關於git merge,rebase合並的差別,以及*(no branch)的處理。

基礎上 並且 以及 們的 mce ron 就會 恢復 tin

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雖好可不要貪杯。rebase除了 --continue外,還有 --skip 和 --abort 操作,其中skip會忽略自己的提交,而更新為遠程倉庫版本;abort會放棄本次合並操作,回到rebase之前的狀態。

關於git merge,rebase合並的差別,以及*(no branch)的處理。