mancuoj

mancuoj

Better late than never.
github
twitter

GitHub 合併 PR 的三種策略

一般來說,我們在創建 PR 時會有一個通用的工作流程:

  1. 創建一個分支,比如 feature
  2. 提交 PR
  3. 讓別人 review
  4. 根據 review 意見修改
  5. 合併 PR 到主分支

但這個 feature 分支可能會有很多次提交,如何合併到主分支就成為了一個問題,GitHub 會給你三個選項:

image

創建一個合併提交#

創建一個連接兩個分支歷史記錄的 "合併提交"

image

我們可以在本地模擬圖中這個過程,首先在主分支創建三個提交,使用 git log --oneline --graph 可以看到提交記錄如下:

* b8472e4 (HEAD -> main) add c.txt
* 2db7159 add b.txt
* b5b52d8 add a.txt

然後在新的分支 git checkout -b feature 創建兩個提交:

* 9770b82 (HEAD -> feature) add e.txt
* 4e65cc4 add d.txt
* b8472e4 (main) add c.txt
* 2db7159 add b.txt
* b5b52d8 add a.txt

切回主分支,使用命令合併:

git checkout main
git merge --no-ff feature

再次查看記錄:

*   7da24fd (HEAD -> main) Merge branch 'feature' into main
|\  
| * 9770b82 (feature) add e.txt
| * 4e65cc4 add d.txt
|/  
* b8472e4 add c.txt
* 2db7159 add b.txt
* b5b52d8 add a.txt

如上,GitHub 在幕後使用 git merge --no-ff 的默認選項會創建一個連接兩個分支歷史記錄的合併提交。

這種方法的優點就是保留了所有的歷史記錄以及各個時間節點,缺點就是多分支或者長期分支會一團亂麻。

壓縮並合併#

將分支中的所有提交壓縮替換為單個提交後合併

image

依舊來嘗試本地模擬,首先 git reset --hard b8472e4 回到合併前:

* b8472e4 (HEAD -> main) add c.txt
* 2db7159 add b.txt
* b5b52d8 add a.txt

使用 git merge --squash feature 壓縮合併,然後編寫適當的提交消息。

最後主分支的提交記錄如下:

* 52c548d (HEAD -> main) add d.txt and e.txt
* b8472e4 add c.txt
* 2db7159 add b.txt
* b5b52d8 add a.txt

可以看出這種方法的優點就是主分支歷史清晰且線性,一個功能用一個提交解決,但是缺點就是丟失了合併以及各個獨立提交的上下文信息,甚至沒法知道這個分支到底合併沒有。

另一種 Squash 的方法#

使用交互式 rebase 命令實現更細緻的操作:

git checkout feature
git rebase -i main

選擇 squash 將後面的提交融合到前一個提交:

pick 4e65cc4 add d.txt
squash 9770b82 add e.txt

編寫適當的提交消息,此時 feature 分支提交記錄變為:

* f37e60f (HEAD -> feature) add d.txt and e.txt
* b8472e4 (main) add c.txt
* 2db7159 add b.txt
* b5b52d8 add a.txt

最後回到主分支合併即可(當然你也可以用 cherry-pick 合併單獨或組合的提交):

git checkout main
git merge feature

Bonus#

這種搞壞提交記錄的操作怎麼恢復?

git reflog
# 你會看到你做的所有 git 操作,找到搞壞的前一步 reset 即可
git reset HEAD@{index}

Rebase and merge#

所有提交都會被添加合併到主分支的 "頂部"

沒圖,但是可以從描述中了解到主分支最後的結果應該是:

image

恢復分支狀態,然後執行以下操作:

git checkout feature
git rebase main

git checkout main
git merge feature

完成後主分支提交記錄如下:

* 9770b82 (HEAD -> main, feature) add e.txt
* 4e65cc4 add d.txt
* b8472e4 add c.txt
* 2db7159 add b.txt
* b5b52d8 add a.txt

優點是主分支歷史清晰線性,沒有多餘的合併提交,其他分支的提交歷史也會直接保存在主分支記錄裡。

缺點與 squash 合併類似,並且更多小提交可能會影響對大局的注意力。

建議#

所有的選擇都是 trade-off 的結果,應該權衡這幾個關鍵的因素:

  • 團隊偏好
  • 提交歷史記錄:完整還是清晰?
  • 更小的提交還是整個功能的完整提交
  • 有無長期運行的分支
  • ...

我只有一個建議:多提交,多寫 PR,不要堆積代碼,更小的代碼片段意味著更容易的 code review,更簡單的單元測試以及更符合單一職責原則的代碼。

參考#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。