git中的cherry-pick,revert和rebase都使用的是3-way合並策略,下面就來看看這3個方法使用的merge-base,ours和theirs分別是什么。
cherry-pick
假如有如下的提交歷史,使用命令git cherry-pick alt(當前branch是master),那么merge-base就是加陰影的commit 1,ours就是加陰影的commit 3,theirs就是加陰影的commit 2。
revert
假如有如下提交歷史,使用命令git revert master~2,那么merge-base就是加陰影的commit 1,ours就是加陰影的commit 3,theirs就是加陰影的commit 2.
rebase
假如有如下提交歷史,每一個提交都向一個文件a里面增加一行,比如commit 1向文件a里面寫入1,commit 2向文件a里面寫入2,依次類推。使用命令git rebase --onto master alt1 alt2時,merge-base,ours,theirs分別是什么呢?
當使用rebase命令時,git如做如下3件事:
1 確定要rebase的commit是什么,這里要rebase的commit就是alt1..alt2。alt1..alt2表示從alt2可reachable的commit當中減去從alt1同樣可以reachable的commit,這里就是commit 10,commit11,commit12;
2 使用一個匿名branch指向alt2
3 將alt2 reset到新的base,即master
如下圖所示:
接下來git會依次將commit 10,commit 11, commit 12 rebase到新的alt2上。如果在rebase commit 10發生了沖突,那么merge-base就是commit 6,ours就是alt2指向的commit 5,theirs就是commit 10。如果commit 10 rebase成功后的commit記為commt 10’(此時alt2會指向commit 10'),接下來rebase commit 11如果也發生了沖突,那么merge-base同樣是commit 6,ours是commit 10',theirs是commit 11。當rebase完成之后如果所示:
由於rebase之后commit 10,commit 11,commit 12沒有被任何分支引用,它們最后會被git移除。
rebase有一個特殊的情況如下圖所示:
如果運行命令git rebase --onto master alt1 alt2,要被rebase的commit應該是alt2上的commit 7,commit 8, commit 10,但是由於alt1(在git rebase --help中,alt1被稱為upstream),上面也有commit 7和commit 8,它們對文件a所做的修改時一樣的,這時,git只會rebase alt2上的commit 10,相應merge-base也會成為alt1上的commit 8,最后的結果如下圖,rebase完成之后,虛線框中的commit 7,commit 8, commit 10同樣會被git移除。