這邊收到伙伴的來信,詢問關於使用 cherry-pick 上的疑惑。
在 來撿 commit 一文中已經介紹過 cherry-pick 了。
主要是用來撿想要的 commit 但在使用上伙伴產生了疑惑,就讓我們來看一下吧。
首先,我們建立一個檔案,名為 index.txt 裡面有三行,分別是:
第一行
第二行
第三行
然後做了一個 commit
commit 51f33baeac4aef3a8aaf6a2d6a4cbb124f25f20c (HEAD -> master)
Author: Logo Kuo <logo@forblind.org.tw>
Date: Fri Jul 31 00:03:36 2020 +0800
原始 index.txt
接下來,把 index.txt 裡的第二行改成「修改第二行了」,也加了第四行,檔案內容變這樣:
第一行
修改第二行了
第三行
我是第四行
一樣做個 commit:
commit c69bfc015bb98ec13db6167172b23d856c99c6be (HEAD -> master)
Author: Logo Kuo <logo@forblind.org.tw>
Date: Fri Jul 31 00:07:34 2020 +0800
改第二行加第四行
最後,我們再把第三行刪掉,一樣做一個 commit:
commit aec61567f3eb0f6fb7cb27fe6c244ddb0b6ee332 (HEAD -> master)
Author: Logo Kuo <logo@forblind.org.tw>
Date: Fri Jul 31 00:11:05 2020 +0800
刪第三行
所以關於 index.txt 總共有三個提交。
我們原本是在 master 主幹道,現在切換到 new_test 這個分支。
在這個分支目前完全沒有 index.txt 這個檔案。
我們如果直接撿第三個 commit 會怎麼樣:
$ git checkout new_test
Switched to branch 'new_test'
$ git log -1
commit 21d3781343c4fb29d7f94ef2449a7fe71d9f17d8 (HEAD -> new_test)
Author: Logo Kuo <logo@forblind.org.tw>
Date: Thu Apr 16 17:34:35 2020 +0800
修改 abc.txt
$ git status
On branch new_test
nothing to commit, working tree clean
$ git cherry-pick aec6156
CONFLICT (modify/delete): index.txt deleted in HEAD and modified in aec6156...
刪第三行. Version aec6156... 刪第三行 of index.txt left in tree.
error: could not apply aec6156... 刪第三行
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
為什麼不行,因為這個分支我們沒有 index.txt 要怎麼對它做修改,在第三個 commit 並沒有新增一個 index.txt 檔案的動作,
這個是我們在第一個 commit 做的事情。
$ git status
On branch new_test
You are currently cherry-picking commit aec6156.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --skip" to skip this patch)
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Unmerged paths:
(use "git add/rm <file>..." as appropriate to mark resolution)
deleted by us: index.txt
no changes added to commit (use "git add" and/or "git commit -a")
他告訴我們 index.txt 沒有在工作區,那我們直接把它加進來:
$ git add index.txt
$ git commit -m '加入 index.txt'
[new_test a970dc8] 加入 index.txt
Date: Fri Jul 31 00:11:05 2020 +0800
1 file changed, 3 insertions(+)
create mode 100644 index.txt
$ git log -1
commit a970dc84dfb5da1e8e4fa3c4d74e06e1e87f942f (HEAD -> new_test)
Author: Logo Kuo <logo@forblind.org.tw>
Date: Fri Jul 31 00:11:05 2020 +0800
加入 index.txt
趕快來看一下 index.txt 的內容:
$ cat index.txt
第一行
修改第二行了
我是第四行
檔案的內容是完整的,看起來就是第三個 commit 提交的版本。
那位伙伴的問題在於把 commit 想成是前面一個個 commit 的累加,
也就是說,如果我直接撿第三個 commit 出來的結果會不完整,因為我沒有第一和第二個 commit.
經過上述的實驗,我們發現這樣的想法是錯誤的,
如果是這樣的話,撿 commit 是沒意義的,因為每個 commit 都要靠上一個 commit 來累積,
那直接撿最後一個行不通,一定要往回撿,那就全部 merge 了,何必單獨撿 commit.
所以,我們要有個正確的概念,就是可以把每個 commit 想成是單獨唯一的,
你撿了這個 commit 就是擁有這個 commit 所有看到的結果。
因此,你不需要考慮他的前一個 commit 做了什麼,你只要確定這個 commit 的結果是你要的,你就可以把他撿過來了。
像我們經常會在一個分支裡面推了好幾個 commit 例如,第一個新增刪除功能,第二個是把刪除的表格調整好,第三個是新增修改功能。
結果第三個新增修改功能時不小心把刪除功能搞壞了,
所以我們只要撿第二個 commit 就會有新增的刪除功能且表格是調整好的。
這樣我們的主幹道就會很簡潔,就挑完成且確定沒問題的 commit 過來就好了。
另外,使用 cherry-pick 後面使用空格來隔開多個 commit 一次撿多個 commit 時,
它不會自動幫我們 merge 在一起,而是一個個撿過來,如果要合併可以考慮看 合併 commit 這篇。