轉載自:https://segmentfault.com/q/1010000007704573/
我猜現實中的情況是這樣的:
使用 git 的人群中,不會用 rebase(哪怕是基礎功能的)的至少一半(這個估計恐怕很保守了)
剩下一半里真正理解何時應該正確 rebase 的恐怕也就一半……
merge 還是 rebase 并不是一個二者選其一的問題,而是應該根據具體情況來選擇使用,而這個“具體情況”在現實中實在是不好一一列舉出來了,對于大多數開發者來說在團隊中的職能比較單一,也不是經常有機會遇到,所以在這里我只總結兩個人人都應該理解并遵守的準則:
當你從 remote 去 pull 的時候,永遠使用 rebase(除了一個例外,后面會講)
當你完成了一個功能(假定你是單獨開本地分支去做的)后打算合并到主干分支的時候,永遠使用 merge
開發者應當理解:不同的合并策略影響的或許不是最終的代碼結果,但卻會影響 git 如何記錄提交的歷史(盡管很多時候這種理解只對個別人受益,而對自己沒有什么影響)。其他的人在使用這些歷史的時候(比如 code review 的時候,或者 bisect 的時候等等)會因為過去你做過的事情而感到無比幸福或痛苦。
第二點比較容易理解,把開發一個功能的具體細節隱藏在本地分支中,而把最終的結果作為一條完整的記錄合并(merge)到主干分支去。
關鍵是第一點。大多數情況下大家會選擇默認的 pull,也就是 fetch + merge,于是我們會看到主干上不停的出現 Merge commit xxx into xxx 之類的干擾信息。如果所有的人都圖方便這么干,那就永遠都別想有干凈漂亮的歷史樹了,取而代之是類似這樣的東西:
如果你去 clone 一個正確使用 git 的項目,你絕對不會看到上圖這樣亂七八糟的 master。為什么呢?答案就是:git pull –rebase,這條命令會使用 rebase 來代替默認的 pull 對合并的歷史樹進行變基處理,就可以避免因為無法快進(fast forward)而產生的額外合并記錄。
現在絕大多數的 git 客戶端都允許設置 git pull 的默認行為是 –rebase,所以掌握了這個訣竅可以讓大部分的日常拉取操作都產生清爽漂亮的歷史記錄,但這并不是完美的結局。有一種例外是這樣的:
在你使用 git merge 完成了一個功能分支向主干分支的合并之后(當然是 –no-ff 的)
在你運行 git fetch 發現遠程主干又領先你若干提交
此時你若 git pull –rebase,你會發現你剛才合并功能分支的記錄沒了……
這是因為變基會忽略合并記錄,因此變基命令會有一個特別的參數叫做:–preserve-merges 用于重建被忽略的合并記錄。所以比 git pull –rebase 更好的方案就是用 git fetch + git rebase -p 代替之。
當然這個僅針對上面提到的特殊情況,隨著 git 的升級說不好哪一天就不存在這種問題了也不一定。我一般都不會遇到這種情況,因為我都是這么做的:
完成功能分支之后先不 merge,而是回到主干分支去 git pull –rebase
如果主干有更新,rebase 更新的內容到功能分支來預檢一下,看看在加入了最近別人的改動之后我的功能是否依然 OK(在這個過程中可能會有沖突處理,別怪我沒提醒哦)
一切就緒之后再次 git fetch 主干看看有沒有變動(因為在第二步的進行期間沒準又有人 push 了新的變化),有的話重復第二步,沒有則——
合并功能分支到主干然后 push,收工。
我這么做可以避免前面提到的意外,看似復雜了些但其實做熟練了之后也沒什么難度,更重要的原因是 git rebase -p 是有缺陷的:
不能和 git pull 連用,一條命令分成倆,怎么都覺得“虧”了(雖說你可以寫腳本,但最好不要因為習慣了之后反而有時候會害了你)
由于無法和 git pull 配合使用,所以你必須指明目標分支給 rebase,這一點比較煩人,特別是很多 GUI 客戶端壓根不支持 git rebase -p 的時候(我經常會在 CLI/GUI 之間切換環境使用 git)
ORIG_HEAD 會被破壞。
ORIG_HEAD 在很多情形下非常有用,比如說你可以用 git log -p -reverse ORIG_HEAD 來回看最近一次合并所產生的所有變化等等。–preserve-merges 會讓它失去本來應該指向的位置,你不得不先找到正確的 hash 來代替它,這會有點煩。
以上答案最終說明一件事情,現實的復雜性永遠超出你在菜鳥時期所能做出的想象,真想把 git 用好那就要在日常工作的基礎上好好理解 git 的工作原理吧,可以去看官方網站電子書(中文版),里面的 git internal 一節仔細看懂之后,該用什么命令心里就有數了。
補充一點:如果你的團隊不在乎主干分支上有很多不重要的干擾提交記錄,那你可以始終使用 rebase,這樣至少可以不會出現很多分岔,處理得當也可以得到干凈(但是啰嗦)的主干分支歷史記錄。