設想這樣的場景,
周一,我們為了開發一個新功能,從master上拉出來一個feature001.R1分支,進行功能開發。
周二,master上發現bug,由其它同事從master上拉出一個bug001.R1分支,進行bug修復。
周三,bug修復完成,合並回master。
周四,我們的功能開發完成,此時要如何把feature001.R1合並到master?
如果直接切換到master進行 merge 操作,可以完成合並,但是合並之后,在master分支執行下面的命令,查看提交歷史記錄
> git log --graph --pretty=oneline --abbrev-commit
會看到下面的圖形
* e4d20d9 Merge branch 'feature001.R1'
|\ | * f72412a 功能開發-001,v2 | * b943b68 功能開發-001,v1 * | 991f559 修復bug-001,v2 * | 2482dcd 修復bug-001,v1 |/
* 71df2e0 init
看上去commit記錄不太干凈,受分支上的提交記錄污染了。
出現這種情況,是因為拉出feature001.R1分支的從master基點已經落后了。
周四,功能開發完成時,先不要合並feature001.R1,而是:
1. 切換到master分支,執行`git pull`,將最新的master拉下來。
2. 切換回feature001.R1分支,執行 `git rebase master`,這是干什么呢?簡單地說,它重置了feature001.R1分支的基線,就是將拉出feature001.R1分支的master基點移動到master的最新位置,就好像先發現bug,創建bug分支、解決bug、合並bug分支到master,然后才拉出功能分支feature001.R1,這個過程中,可能會有沖突,需要解決沖突,再rebase continue...。
實際上,rebase背后做了什么?git是如何移動基點的呢?
首先,git會把feature001.R1分支上的所有commit取消掉;
其次,將feature001.R1分支上被取消的操作制作成 patch 文件,保存起來('.git/rebase'目錄);
然后,把feature001.R1分支更新到最新的master分支,相當於將最新的master分支合並到feature001.R1,但不產生任何合並記錄,也相當於在最新的master分支上重建了feature001.R1分支。
最后,把上面保存的 patch 文件應用到 feature001.R1分支上,此過程可能產生沖突。
3. 切換到master分支,merge合並 feature001.R1分支
這樣完成合並之后,就提交歷史就不會有分叉了,
> git log --graph --pretty=oneline --abbrev-commit * 15892dc 功能開發-002
* a3cb265 修復bug-002,v2 * 958880e 修復bug-002,v1 * e4d20d9 Merge branch 'feature001.R1'