在日常開發中,我們的Git提交原則經常是小功能多次提交,但是有時需要在完成功能之後將多個連續的提交合併成一個,或者進行分支合併時,只保留一個提交,以保證分支簡介,這時就需要進行squash操作,兩種分別稱爲 Rebase Squash 和 Merge Squash。這篇tip主要記錄如何處理這兩種操作以及之間的區別,
<!--more-->
Rebase Squash
用來將多個連續的提交合併爲一個,以下面的提交記錄爲例,master
是主分支,分支 featureY
提交了一系列的修改:
$ git lg
* 392dc11 - (HEAD -> featureY) Y5 (5 minutes ago) <qiwihui>
* 740e7d2 - Y4 (5 minutes ago) <qiwihui>
* b54cd87 - Y3 (5 minutes ago) <qiwihui>
* fb3a5cf - Y2 (6 minutes ago) <qiwihui>
* 61b5ff9 - Y1 (6 minutes ago) <qiwihui>
* 220e45c - (master) feature X (7 minutes ago) <qiwihui>
其中,lg
是如下命令:
[alias]
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --
這裏我們需要合併 featureY
功能分支上的 Y1
到 Y5
這五個提交爲一個。git提供瞭如下命令:
git rebase --interactive HEAD~[N]
# 或者
git rebase -i HEAD~[N]
其中 [N]
表示需要合併的數量,從最近一個提交開始數,這裏爲5
。在命令行輸入 git rebase --interactive HEAD~5
進入編輯器進行選擇。
注意,這裏的提交順序是 反 的,從最早的 Y1
開始:
pick 61b5ff9 Y1
pick fb3a5cf Y2
pick b54cd87 Y3
pick 740e7d2 Y4
pick 392dc11 Y5
對應需要合併的提交,將pick
改成squash
(或者簡化爲s
),修改之後爲:
pick 61b5ff9 Y1
s fb3a5cf Y2
s b54cd87 Y3
s 740e7d2 Y4
s 392dc11 Y5
保存並關閉編輯器,這是編輯器會自動跳出並需要你提交一個新的提交:
# This is a combination of 5 commits.
# This is the 1st commit message:
Y1
# This is the commit message #2:
Y2
# This is the commit message #3:
Y3
# This is the commit message #4:
Y4
# This is the commit message #5:
Y5
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Thu May 9 13:45:03 2019 +0800
#
# interactive rebase in progress; onto 220e45c
# Last commands done (5 commands done):
# squash 740e7d2 Y4
# squash 392dc11 Y5
# No commands remaining.
# You are currently rebasing branch 'featureY' on '220e45c'.
#
# Changes to be committed:
# new file: featY
#
可以看到,Git提供了詳細的信息指導提交,只需要修改成你需要的信息即可,比如 featureY
,然後保存。這時就完成了修改,修改之後的提交信息如下:
$ git lg
* 1b07941 - (HEAD -> featureY) featureY (3 minutes ago) <qiwihui>
* 220e45c - (master) feature X (36 minutes ago) <qiwihui>
Merge Squash
用於在合併分支時,最後只在合併後的分支上保留一個提交。同樣以上面的代碼提交爲例子。
$ git lg
* 392dc11 - (HEAD -> featureY) Y5 (5 minutes ago) <qiwihui>
* 740e7d2 - Y4 (5 minutes ago) <qiwihui>
* b54cd87 - Y3 (5 minutes ago) <qiwihui>
* fb3a5cf - Y2 (6 minutes ago) <qiwihui>
* 61b5ff9 - Y1 (6 minutes ago) <qiwihui>
* 220e45c - (master) feature X (7 minutes ago) <qiwihui>
$ git checkout master
$ git merge --squash featureY
Updating 220e45c..392dc11
Fast-forward
Squash commit -- not updating HEAD
featY | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 featY
此時,分支featureY
保持不變,同時在master
上多了一個未被提交的更改:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: featY
這些更改是分支featureY
中所有提交的合併,現在只需要提交這些更改就可以了:
git commit -m "featureY"
區別
從以上的擦坐過程可以看出兩者之間的差別:Rebase Squash會合並之前的提交,之前的記錄會消失,而Merge Squash只會在合併的分支上新生成提交,原來的那些提交熬還會保留。
多說一點
如果需要合併的提交數量很多,數數容易出錯,可以使用提交哈希來識別:
git rebase --interactive [commit-hash]
這個[commit-hash]
是需要合併的提交之前的一個提交:
$ git lg
* 392dc11 - (HEAD -> featureY) Y5 (5 minutes ago) <qiwihui>
* 740e7d2 - Y4 (5 minutes ago) <qiwihui>
* b54cd87 - Y3 (5 minutes ago) <qiwihui>
* fb3a5cf - Y2 (6 minutes ago) <qiwihui>
* 61b5ff9 - Y1 (6 minutes ago) <qiwihui>
* 220e45c - (master) feature X (7 minutes ago) <qiwihui>
這裏,需要使用 220e45c
而不是 61b5ff9
。