rebase介紹
一、背景
遠程倉庫有oh4w-dev
和oh4k-dev
兩個分支,oh4k-dev
是基于oh4w-dev
開發到80%的代碼新拉的分支;此后兩條分支同步開發,當oh4k-dev
開發完成,oh4w-dev
還在開發階段,oh4k-dev
需要拉取到oh4w-dev
自分出oh4k-dev
后的最新提交。
二、git pull VS git rebase
有兩種方法,git pull
和git rebase
。
git pull
git pull
其實是git fetch
和git merge
的組合
當執行git pull
時,相當于執行了git fetch
從遠程倉庫拉取最新代碼、git merge
將拉取的最新代碼和本地代碼合并
使用git pull
,雖然在存在沖突時,會多出無意義的一條提交記錄“Merge…to…”,但能清楚地知道當前分支上誰合了代碼以及合代碼的時間先后順序
git rebase
git rebase
則是將當前分支的提交歷史,建立在指定分支上的和當前分支的公共祖先節點的最新提交上(不論提交的時間先后順序)
三、選擇git rebase的理由
目前的情況使用git rebase
更加合適,因為oh4w-dev
仍然在開發過程中,即使使用git pull
合并一次代碼,下次oh4k-dev
再次拉取oh4w-dev
最新代碼時,上次合并過的沖突還需要重復處理;而使用git rebase
合并一次提交歷史,oh4w-dev
和oh4k-dev
的提交記錄的公共祖先節點已經更新了,無需再處理一遍上次處理過的沖突
四、使用git rebase遇到的問題
問題一
本地倉庫中,與遠程分支oh4w-dev
和oh4k-dev
對應的分支分別是local-oh4w-dev
和local-oh4k-dev
站在local-oh4k-dev
分支使用git rebase local-oh4w-dev
拉取local-oh4w-dev
的最新提交歷史,很幸運沒有沖突,但在執行git push --force-with-lease
進行強制提交時終端報錯
分析了一下原因,是因為這個項目在git push
提交修改到Gerrit遠程倉庫時,每次提交都需要攜帶Change-Id
,Change-Id
是Gerrit等代碼審查工具用來跟蹤提交的唯一標識符,如果Gerrit判斷推送的變基后的提交歷史中包含已經被合并到主分支或已經關閉的修改(即存在相同的Change-Id),則會導致提交被拒絕
還有一點,推送的遠程分支是Gerrit中的refs/for/<branch>
,這是一個特殊的引用命名空間,用于接受代碼審查的推送,Gerrit不會像傳統分支那樣檢查其狀態;而git push --force-with-lease
的核心邏輯是檢查遠程分支的當前狀態是否與本地引用的遠程分支狀態一致,所以git push --force-with-lease
對refs/for/oh4k-dev
是無效的,與普通的git push
幾乎相同
解決方法
如果Change-Id
沖突,可以重新生成新的Change-Id
:
-
如果是單個commit記錄
1.使用git commit --amend
修改提交記錄
2.刪除舊的Change-Id
3.esc
退出編輯模式
4.輸入:wq
保存
5.Git會自動生成一個新的Change-Id
6.git push origin local-oh4k-dev:refs/for/oh4k-dev
將本地的變更推送到遠程 -
如果有多條提交記錄需要修復,可以使用交互式變基
1.使用git rebase -i HEAD~n
選擇最新的n條commit記錄進入編輯模式
2.輸入i
開啟編輯操作
3.將需要修改的提交記錄的pick
改為edit
4.
esc
退出編輯模式
5.輸入:wq
保存
6.在每一條提交記錄處停留,用處理單個提交記錄的方式處理
7.每處理完一條,執行git rebase --continue
,直到變基結束
8.git push origin local-oh4k-dev:refs/for/oh4k-dev
將本地的變更推送到遠程
問題二
變基結束,將本地合并后的提交歷史上傳到遠程,意味著,之前在local-oh4k-dev
上提交過的修改,需要重新提交一次,可能會存在沖突
解決方法
1.使用git rebase -i HEAD~n
啟動交互式變基
2.修改第一條提交之外的狀態為fixup(自動合并修改但丟棄提交信息)或squash(自動合并修改且允許修改提交信息)
3.如果產生沖突,解決完沖突后git add .
,git rebase --continue
繼續變基
4.變基結束git commit --amend
生成新的Change-Id
5.最后git push origin local-oh4k-dev:refs/for/oh4k-dev
推送本地變更
問題三
本地的提交歷史由于進行了rebase已經改變,而git push
不會覆蓋遠程倉庫的提交歷史,只是新增了剛剛push上去的新的變更,所以本地的提交歷史和遠程倉庫還是不一致的,可以通過git reset --soft origin/oh4k-dev
,將兩者進行同步
思考
這樣一條一條提交記錄去刪除,記錄較少的情況下還好處理,一旦數據量過大,很浪費時間,看看可以不可以一鍵刪除?