情景
你正在做一個專案,然而在過去的某個時候,你把兩個重大的改動提交到了一個版本A中。
直到又進行了幾次提交之後,你才發現有必要將之前那兩個重大改動拆分成版本A和版本B。
當前的提交日誌如下所示:
commit 4a6a4088ecbe26d7f85db703e9c0a493aaac9675
Author: Wray Zheng
Date: Thu March 25 17:06:19 2017 +0800
add new functions
commit 1c6a58f2c80b276b24495558cffedd13998a766a
Author: Wray Zheng
Date: Thu March 25 17:04:23 2017 +0800
Two Big Changes
commit 3157d5c2c16938d2ba1d68eae8fb5a26f87365ea
Author: Wray Zheng
Date: Thu March 25 17:03:06 2017 +0800
first commit 複製程式碼
下面,我們就要將"Two Big Changes"對應的提交拆成兩個提交。
1. 進入 rebase 互動模式
git rebase -i 複製程式碼
此處 SHA-1
為版本A的上一個提交的校驗和。
以上面的提交日誌為例,可以輸入以下命令來進入互動模式:
git rebase -i 3157d5c複製程式碼
如果版本A不是上述情況,而是第一個提交,則可以使用 --root
選項:
git rebase -i --root複製程式碼
之後 git 會開啟一個檔案,給出指定提交之後的所有提交讓你進行修改。
pick 1c6a58f Two Big Changes
pick 4a6a408 add new functions
# Rebase 3157d5c..4a6a408 onto 3157d5c
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out複製程式碼
2. 將版本A對應的命令改為 edit
我們找到版本A,即"Two Big Changes"所對應的提交。
將版本A前面的 pick 改為 edit,這會讓 git 在 rebase 過程中停留在版本A,讓我們進行修改,然後再繼續 rebase 過程。
改完之後如下所示:
edit 1c6a58f Two Big Changes
pick 4a6a408 add new functions
......複製程式碼
儲存並關閉該檔案,git 就開始了 rebase 過程。
3. 撤銷版本A的提交
我們可以看到 git 在 rebase 過程中停留在了版本A,讓我們進行相應操作。
此時,我們相當於處在剛提交完版本A的環境中。接下來,先撤銷版本A的提交行為,也就是恢復到版本A的前一個版本:
git reset HEAD~複製程式碼
然後可以進入到第 4 步。
如果版本A為首次提交的話,請使用以下的方式解決。
先使用以下命令將第二個改動從暫存區中刪除:
git rm --cached change2.cpp複製程式碼
此時暫存區中只剩下第一個改動了,我們可以將其提交為版本A:
git commit --amend -m "Version A"複製程式碼
然後再提交第二個改動:
git add change2.cpp
git commit -m "Version B"複製程式碼
至此,就完成了改動的分開提交,接下來可以跳到第5步。
4. 分別提交兩個重大改動
撤銷完版本A的提交後,我們就可以把兩個重大改動分開提交了。
git add change1.cpp
git commit -m "Version A"
git add change2.cpp
git commit -m "Version B"複製程式碼
5. 完成 rebase 過程
最後,只要輸入以下命令就完成 rebase 過程啦:
git rebase --continue複製程式碼
大功告成!讓我們來看看這時的提交日誌是不是和我們預期一致。
commit 27aedab1a2a3ae4abb1f194971ae773e9a8017c5
Author: Wray Zheng
Date: Thu March 25 17:06:19 2017 +0800
add new functions
commit a5f065f4736c676cca27c0c716ce732f401c913e
Author: Wray Zheng
Date: Thu March 25 17:51:53 2017 +0800
Version B
commit 56f506b500c1119c3736501e30c0a901a378ae03
Author: Wray Zheng
Date: Thu March 25 17:51:42 2017 +0800
Version A
commit 3157d5c2c16938d2ba1d68eae8fb5a26f87365ea
Author: Wray Zheng
Date: Thu March 25 17:03:06 2017 +0800
first commit 複製程式碼
我們按照預期將版本A拆分成了兩個提交:版本A和版本B。
總結
在這裡,我們使用了互動模式的 rebase 操作。
當我們對版本A進行修改時,git為我們恢復到了當時的狀態,包括工作區、暫存區、倉庫,都變成剛提交完版本A的狀態。
此時,HEAD就是版本A。
我們使用 git reset HEAD~
將倉庫恢復到上一個版本,此時工作區依然保留了版本A的改動。
然後,我們分開提交這兩個變動。最後,通過 git rebase --continue 來完成此次 rebase 操作。