原文:Merging vs. Rebasing
git rebase
一直是初級程序員想遠離的黑魔法,但事實上在開發(fā)團隊小心的使用該命令可以令我們的工作更輕松科盛。本文將git rebase
與git merge
做對比份汗,來看看在典型的Git工作流中引入git rebase
可以帶來什么好處怎憋。
概念縱覽
首先我們要了解git rebase
和git merge
作用是相同的映跟,都可以用來將一個分支上的代碼合并到另一個分支——只是實現(xiàn)方式不同迹卢。
當(dāng)你使用專門的分支開發(fā)feature時惠豺,其他團隊成員如果繼續(xù)向master分支提交银还。就會產(chǎn)生一個分叉的歷史,任何使用Git作為協(xié)同工具的開發(fā)人員應(yīng)該都很熟悉這樣的場景洁墙。
假設(shè)提交到master的代碼跟你正在開發(fā)的feature相關(guān)蛹疯,為了將新的提交合并到feature分支,你有兩個選項:git merge
或git rebase
热监。
Git merge
最簡單的方法就是使用以下命令將master分支合并到feature分支:
git checkout feature
git merge master
或者簡化成一行命令:
git merge master feature
該操作會在feature分支上產(chǎn)生一個新的“合并提交”捺弦,將兩個分支的歷史合并在一起,如圖示這樣:
git merge
很好用因為它是一個非破壞性的操作。當(dāng)前分支不會被改變列吼。因此避免了git rebase
操作可能帶來的所有隱患(詳見下文)幽崩。
然而另一方面,這意味著每一次合并操作都會在feature分支上產(chǎn)生一個額外的“合并提交”寞钥。如果master分支更新頻繁的話會導(dǎo)致feature分支的歷史記錄被污染慌申,令其他開發(fā)者難以理解項目的歷史記錄。
Git rebase
合并操作的另一個選擇是使用git rebase
理郑,例如如下命令蹄溉,將feature分支rebase到master分支:
git checkout feature
git rebase master
該操作將整個feature分支的記錄移到了master分支的頭部,將所有的新提交都并入了master分支香浩。但是不同于"合并提交"类缤,git rebase
通過對原分支上的提交做標記重寫了項目的提交記錄。
使用git rebase
的最大好處是可以得到更干凈的項目記錄邻吭。首先餐弱,它消除了git merge
帶來的無用的"合并提交"。其次囱晴,對比上面的圖我們看到膏蚓,git rebase
可以產(chǎn)生完美的線性歷史記錄——可以方便的使用git log
,git bisect
和gitk
追蹤提交記錄畸写。
但是驮瞧,在追求干凈的提交記錄的同時還要權(quán)衡兩個方面:安全性和可追溯性。如果沒有遵循git rebase
的最佳實踐枯芬,重寫項目的歷史記錄可能會毀滅合作工作流论笔。另外,git rebase
丟失了合并操作的上下文信息——我們無法得知某一次合并操作具體發(fā)生在何時千所。
交互式rebase
交互式的rebase可以對要移到新分支上的提交記錄進行修改狂魔,它能夠完全控制分支的提交記錄,因此比自動rebase功能更強大淫痰。通常最楷,在將一個功能分支合并到master分支前,可以用其來整理混亂的提交歷史待错。
將-i
傳入git rebase
來進入交互式rebase會話
git checkout feature
git rebase -i master
命令執(zhí)行完成之后會打開一個文本編輯器籽孙,其中列出了所有要被移到新分支的提交:
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
這個列表展現(xiàn)了rebase執(zhí)行之后分支的提交記錄』鸲恚可以通過修改pick
命令或調(diào)整條目順序來改變分支的提交歷史犯建。例如,假設(shè)第二次提交是為了修復(fù)第一次提交中的一個小問題瓜客,我們可以通過fixup
將這兩次提交合并:
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
保存并退出該文件后适瓦,Git會通過該文件的內(nèi)容執(zhí)行rebase沟启。最終項目的提交記錄如圖所示:
通過交互式rebase可以忽略不重要的提交令分支歷史更容易理解,這一點是git merge
無法比擬的犹菇。
Git rebase的金律
現(xiàn)在我們理解了什么是git rebase
,但最重要的是要知道什么時候不要用它芽卿。Git rebase的金律是:永遠不要在公有分支上用它揭芍。
例如,試想一下如果將master分支rebase到feature分支會發(fā)生什么:
這個rebase操作將master分支的所有提交移動到了feature分支的頭部卸例。但問題是這一切都發(fā)生在你本地称杨。其他開發(fā)者依然在原master分支上繼續(xù)工作。因為rebase會導(dǎo)致新的提交筷转,Git會認為你的master分支和其他開發(fā)者的出現(xiàn)了分叉姑原。
唯一同步這兩個版本master的方式是將它們git merge
,但是這樣會導(dǎo)致一個額外的合并提交記錄和包含相同修改的兩次提交(原始master分支和被rebase的master分支)呜舒。不用說锭汛,這是一個令人困惑的情況。
所以袭蝗,在執(zhí)行git rebase
之前唤殴,總是問問自己,“其他人用這個分支嗎到腥?”如果答案是yes朵逝,把手從鍵盤上拿開,考慮使用一種非破壞性的方法來達到同樣的目的(例如git revert
)乡范。否則配名,放心的按自己的喜好去重寫歷史吧。(譯注:修改歷史提交記錄)
Force-Pushing
Rebase過的master分支與遠程倉庫的master分支會存在沖突晋辆,所以Git不允許將rebase過的分支推送到遠程倉庫渠脉。但是可以通過傳遞--force
標簽進行強制推送:
# Be very careful with this command!
git push --force
該操作會將遠程倉庫的master分支替換為rebase過的master分支,這會給團隊的其他成員帶來困擾栈拖。所以连舍,小心使用該命令,除非你知道自己在做什么涩哟。
少數(shù)幾個需要使用強制推送的場景之一是將私有分支推送到遠程倉庫(例如:以備份為目的)后索赏,對該分支上的提交進行了清理。這就像說贴彼,“我不想推之前那版feature分支了潜腻,用這個替換吧”。再強調(diào)一次器仗,一定要確保沒有其他開發(fā)人員在使用該分支融涣。
工作流演練
git rebase
可以根據(jù)團隊的需要或多或少的與現(xiàn)存的Git工作流進行整合童番。這一章,我們來看看在一個feature分支的不同開發(fā)階段威鹿,使用git rebase
能帶來什么好處剃斧。
對于任何工作流來說,要使用git rebase
的第一步是為每個feature創(chuàng)建一個專門的分支忽你。這種分支策略可以幫助我們安全的使用git rebase
:
整理本地分支
將rebase
加入到工作流的一個好處是整理本地進行中的功能分支幼东。通過定期執(zhí)行交互式rebase,可以保證每一次提交(commit)都是有意義的科雳。這可以讓我們在寫代碼時不用擔(dān)心每次提交是不是都有意義——可以之后通過交互式rebase修復(fù)根蟹。
調(diào)用git rebase
時可以傳入兩種參數(shù):父分支(例如master),或當(dāng)前分支的前幾次提交糟秘。在交互式rebase章節(jié)中我們看到了傳入父分支的用法简逮。當(dāng)我們需要整理最后幾次提交時后者比較有用。例如尿赚,以下命令為最后3次提交開啟了交互式rebase霍比。
git checkout feature
git rebase -i HEAD~3
通過指定HEAD~3
嗜愈,我們并沒有移動分支——只是重寫了最后三次提交观堂。注意不包含其他提交懈万。
如果想用這個方法重寫整個分支,git merge-base
命令可以用來追尋feature分支的original base泻蚊。以下命令返回original base的commitID躲舌,可以將該commitID傳給git rebase
:
git merge-base feature master
可以通過這種交互式rebase的用法將git rebase
引入到你日常的工作流中,因為它只會影響本地分支性雄。其他開發(fā)者僅僅會在你開發(fā)完成之后看到一個提交記錄干凈的没卸,易于追溯的feature分支。
但是再一次強調(diào)秒旋,這種用法只針對本地私有分支约计。如果你在和其他開發(fā)者在某一個feature分支上進行合作開發(fā),那么這個分支是共有的迁筛,請不要試圖去重新提交歷史煤蚌。
git merge
無法做到清理本地提交歷史。
作者:李小西033
鏈接:http://www.reibang.com/p/318b4f0f57ff
來源:簡書
簡書著作權(quán)歸作者所有细卧,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處尉桩。