git merge --squash / git rebase -i / git cherry-pick

git merge --squash

git merge --squash {srcBranch} 常用於將feat分支合併至dev時壓縮繁雜的提交日誌,讓合併變得清晰明瞭。

srcBranch上的超前於當前分支的 commits 合併至當前分支,且當前分支不進行commit,合併或解決衝突成功後,允許我們手動做一次 commit log,這樣srcBranch的多個 commits 合併至當前分支時只產生一個commit 了。

git checkout dev
echo 1111 >> foo.txt
git add foo.txt
git commit -m "foo.txt 1111"

git checkout -b feat_1
echo 2222 >> foo.txt && git commit -am "foo.txt 2222"
echo 3333 >> foo.txt && git commit -am "foo.txt 3333"
echo 4444 >> foo.txt && git commit -am "foo.txt 4444"
git log

git checkout dev
# 如果我們直接 git merge feat_1 的話 那 feat_1 的所有提交都會記錄至 dev
# 但我們想簡潔的表徵一下
git merge --squash feat_1

# 手動編寫 log 提交
git commit -m '
foo.txt 2222
foo.txt 3333
foo.txt 4444
'
# 或者使 diff logs 爲模板提交
git commit -v
# 進入 vim 模式 編輯合併的 log
:wq

# 可以看到 feat_1 的 3 log 合併到 dev 上後只有 1 log
git log

--squash 的作用爲只合並源分支的內容到當前分支的stage區,將commit交由我們來決定,這樣便可以整合其他分支的提交日誌。

git rebase -i

切記不可用於協同開發的分支,只能用於獨自使用的分支。

git rebase -i [startPoint] [endPoint]

rebase可以方便我們編輯本分支的commit記錄:合併,修改,刪除。比如我在feat分支上開發測試ok,需要合併到dev分支,但feat上有很多繁雜的commit logs,我們可能並不需要在dev中體現,可能有人想到可以在dev上使用 merge --squash,但如果feat落後dev 很多,這時我們可能需要使用 git cherry-pick commitLogHash的方法將feat中特定的提交合並至dev分支。這時就需要我們在dev的基礎分支上創建一個temp分支,temp merge --squash feat後獲得一次性提交的temp_commit_log,然後切換至dev執行 git cherry-pick {temp_commit_log}合併至dev分支,或者我們可以使用 rebase -i HEAD~N HEAD 的方式合併本分支的多次提交。

合併多條提交記錄至用一條

git checkout dev
echo 1111 >> bar.txt && git add bar.txt
git commit -m "bar.txt 1111"

git checkout -b feat_2 dev
echo 2222 >> bar.txt && git commit -am "bar.txt 2222"
echo 3333 >> bar.txt && git commit -am "bar.txt 3333"
echo 4444 >> bar.txt && git commit -am "bar.txt 4444"

# 開發完成 要講 feat_2 合併回 dev 但不想要太多 feat-2 的 log
git rebase -i dev

-----------------------------------------------------------------------
pick 0483730 bar.txt 2222
pick adf4d92 bar.txt 3333
pick cd1b421 bar.txt 4444

# Rebase 7ffea48..cd1b421 onto 7ffea48 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
-----------------------------------------------------------------------

# 修改至如下
pick 0483730 bar.txt 2222
s adf4d92 bar.txt 3333
s cd1b421 bar.txt 4444
:wq

-----------------------------------------------------------------------
# This is a combination of 3 commits.
# This is the 1st commit message:
# 合併多個日誌
bar.txt 2222
bar.txt 3333
bar.txt 4444
# 編輯後 :wq 保存退出
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Fri Apr 26 14:26:09 2019 +0800
#
# interactive rebase in progress; onto 7ffea48
# Last commands done (3 commands done):
#    squash adf4d92 bar.txt 3333
#    squash cd1b421 bar.txt 4444
# No commands remaining.
# You are currently rebasing branch 'feat_2' on '7ffea48'.
-----------------------------------------------------------------------

# 可以看到三個提交合並至 1 個了
git log
# 不過會造成 HEAD detached from fed40ed
git checkout -b temp
# 查看具體的
git log
git checkout feat_2
git cherry-pick 
# 切換至 dev 合併 feat_2 的日誌會很簡潔 
git checkout dev
git merge feat_2
git log

修改 commit log

git rebase -i [startpoint] [endpoint] 的 startpoint 爲開區間,所以如我們想修改提交的日誌,需要如下

#重建最近一次的提交
git rebase -i HEAD~1
#重建 HEAD~3 - HEAD~2 的兩次提交
git rebase -i HEAD~4 HEAD~2

實例,我們對feat_4foo4做了 4 次提交,日誌如下

git log --pretty=oneline --abbrev-commit
fed40ed (HEAD -> feat_4) foo4 4444
8455d9a foo4 3333
1548e84 foo4 2222
53e837b foo4 1111

重寫最近一次提交的日誌

git rebase -i HEAD~1
#進入交互模式
pick fed40ed foo4 4444

# Rebase 8455d9a..fed40ed onto 8455d9a (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
------------------------------------------------------------------------------
# 修改 pick 爲 reword 即保留本次提交,但要對提交信息做編輯
pick fed40ed foo4 4444
# 保存並退出
:wq
# 會進入日誌編輯模式
foo4 4444

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Fri Apr 26 18:40:09 2019 +0800
#
# interactive rebase in progress; onto 8455d9a
# Last command done (1 command done):
#    reword fed40ed foo4 4444
# No commands remaining.
# You are currently editing a commit while rebasing branch 'feat_4' on '8455d9a'.
#
# Changes to be committed:
#       modified:   foo4
--------------------------------------------------------------------------------
# 修改至你想要的日誌
foo4 4444 modify by rebase::reword
:wq

# 可以看到日誌已經被修改
git log --pretty=oneline --abbrev-commit
7ccdb4c (HEAD -> feat_4) foo4 4444 modify by rebase:reword
8455d9a foo4 3333
1548e84 foo4 2222
53e837b foo4 1111

git rebase -i合併/修改提交記錄的方法如上所示。

git cherry-pick

git cherry-pick的使用場景主要是用於挑選合併某分支上的提交到當前分支。比如我們將feat1合併到了dev,產生了log-dev-feat-1,將feat1合併到了dev,產生了log-dev-feat-2,現在我只想將feat1發佈到測試分支,git merge dev已經不能滿足了,因爲會將log-dev-feat-2一起合並過來。

git checkout dev
git merge feat1
git merge feat2
git log --pertty=oneline
git checkout test
# 挑選合併feat1的提交
git cherry-pick feat1-log-hash

這樣我們就可以靈活的選擇要發佈到測試環境的功能項了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章