git rebase:原來還能這樣合併代碼!
最近,聽到同事討論 Git 的 rebase[1] 命令,我竟沒聽說過,一時有些汗顏,繼續聽,好像與 merge[2] 命令有些關係。我們知道, merge
命令可以將一個分支的代碼整合到另一分支上,那rebase
命令具備同等功效嗎?在實際應用中能不能代替 merge
呢?帶着這些疑惑,我們一起走近rebase
命令。
它是什麼?能解決什麼問題?
對於陌生的命令,我最好奇的是它在實際操作中能解決哪些問題。Git 的 rebase
的中文翻譯是” 變基”,其主要作用是將多個 commit
合併成 1 條或多條之後 ,push
到遠程個人倉庫或上游分支,最終實現合併代碼、改變歷史提交記錄的效果。
看到這裏,大家可能和我想到了一處,以後不小心提交的 bug
記錄是不是可以偷偷刪掉還不被老大發現呢?答案恐怕要讓人失望了,在具體操作中,rebase
合併代碼比 merge
更爲複雜,使用不當可能導致代碼衝突,進而丟失提交記錄。爲了避免這些問題,我們只能在個人分支上執行該命令,對於已經合併到共用倉庫的提交最好還是不要再進行修改了。
既然操作這麼麻煩,還不能刪除 bug
記錄,那修改歷史提交記錄目的又何在呢?面對不能改變的客觀事實,那我們只能改變一下自己的觀念了,最好,再換個需求。有的人想記錄實際發生過的事情,有的人只想記錄項目過程發生的事情,需求不同選擇自然也不同。使用 rebase
前後的效果圖如下:
使用場景
在解決了多次衝突、detached
、no branch
的問題後,我對rebase
命令的理解又深刻了些,最後總結出以下幾種使用場景:
-
個人分支下,
push
到遠程倉庫時將本地多個commit
合併爲 1 個或多個; -
個人分支下,將已
push
到遠程倉庫的commit
合併爲 1 個或多個; -
不同分支下,當前分支合併到上游分支時,將多個
commit
合併爲 1 個或多個。
記錄三種場景的模擬過程
場景一:個人分支下,push
到遠程倉庫時將本地多個 commit
合併爲 1 個或多個
1.git checkout develop
,切換到 develop
個人分支;
sh test.sh
,運行腳本在本地生成三條 commit
記錄;
echo '1' >> README.md
git commit -am '1'
echo '2' >> README.md
git commit -am '2'
echo '3' >> README.md
git commit -am '3'
3.git rebase -i
,打開 rebase
的互動界面,將紅框中的 pick
修改爲 s
或 squash
(將該 commit
與前一個合併) 並保存;commit
信息。不需要的 commit
信息可以註釋,默認合併展示;git push
至遠程倉庫後查看歷史提交記錄。
場景二:個人分支下,將已 push
到遠程倉庫的 commit
合併爲 1 個或多個
1.git checkout develop
切換到個人分支;
2. 模擬三條 commit
記錄並 push
到遠程倉庫;
git rebase -i HEAD~3
獲取最近 3 次的歷史提交記錄,將紅框中的 pick
修改爲 s
或 squash
並保存;commit
信息。不需要的 commit
信息可以註釋掉,默認合併展示;git push
至遠程倉庫後查看歷史提交記錄。
場景三:不同分支下,當前分支合併到上游分支時,將多個 commit
合併爲 1 個或多個
1.git checkout develop
,切換到個人分支;
2.git rebase -i master
,將 develop
分支的修改變基到 master
分支上,流程與前面兩個場景相同;
3.git checkout master
,回到 master
分支;4.git merge develop
,使用 merge
合併。
git rebase 與 git merge 的區別
前面說過,rebase
與 merge
命令都可以用來合併分支,區別是 rebase
合併時還可以修改 commit
歷史記錄,比 merge
多了一個作用。表面看起來rebase
似乎更勝一籌,但在實際操作中兩者各有利弊,建議按需選擇。在實際應用中,我們可以遵循一個原則:下游分支更新上游分支的提交時使用 rebase
,上游分支合併下游分支時使用 merge
。
知其然,還要知其所以然,下面我們通過兩張圖片簡單介紹一下它們的合併原理。
-
git rebase
是把當前分支的提交以打補丁的形式按照原有順序依次移動到上游分支上。
-
git merge
是把要合併的兩個分支上最新的提交與分叉前的提交三方簡單合併在一起。
這裏補充一下,在文章開頭我說到以往合併分支時我並未直接使用 rebase
或merge
命令,這是因爲git pull
等同於git fetch
+git merge
,在這次學習後,rebase
也將成爲我的常用命令之一。
使用 rebase 常見問題
最後,列舉一下我在使用 rebase
過程中遇到的問題,以及我是怎樣解決的。
-
假如真的不小心在共用分支上執行了
rebase
命令,那麼其他人git pull
時都需要加上rebase
,如:git pull --rebase
。 -
rebase
過程中遇到衝突,分支停留在no branch,rebasing <branch name>
狀態,可以執行git rebase --abort
命令取消當前rebase
進程,或者處理完衝突後執行git rebase --continue
命令繼續。 -
HEAD detached from <commit id>
,切換到某個分支時HEAD
會移動到指定分支,切換到某個提交時它便處於detached
狀態,解決辦法是創建臨時分支。
參考資料
[1]
rebase
: https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA
[2]
merge
: _https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E6%96%B0%E5%BB%BA%E4%B8%8E%E5%90%88%E5%B9%B6#basic_merging
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/JxkhaqvsTY5mLO2hwdCGgQ