git忠实记录自己提交的每一次修改,修改历史记录不是一个好习惯。不过在日常使用中,偶尔也有遇到需要修改过去提交记录的情况,比如,commit之后发现message少写了一些功能说明(如果想撤回整个commit修改,请自行搜索*git revert*哈),有时候甚至是在十几次提交之后才发现某次提交说明有误。又比如,因为某个功能比较复杂,作者想通过多次commit来记录修改以便方便回退,但是在推到项目仓库,发出合并请求的时候,意识到主仓库不需要记录太多commit时,就有了将请求合并的需求。

修改历史提交说明

git的rebase命令提供了对历史提交进行修改的功能。

  • git log 找到想要修改的commit的上一个commit的id

  • git rebase -i [ID] 进入交互模式,此时可以看到形如

    pick ed03fd1 test
    pick f5c2a41 test
    # Rebase fa0ab51..f5c2a41 onto fa0ab51 (2 command(s))
    #
    # 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
    

非注释部分即为刚那个ID之后的两次提交(知道为什么rebase命令后跟的是上一个commit了吧),最新的在最下面。根据注释部分的说明,将第一行的pick改为e,然后:wq退出,此时HEAD会返回到该提交处,执行git commit --amend "修改之后的message",再执行git rebase --continue即可将该提交的message修改并返回到最新状态。

合并历史提交

合并历史提交与上个操作基本相同。调出上步中的交互界面后,将想要合并的commit的pick改为s,然后:wq退出,此时后进入下一个交互界面,形如

# This is a combination of 2 commits.
# The first commit's message is:

first commit

# This is the 2nd commit message:

second commit

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Mon May 30 21:23:57 2016 +0800
#
# rebase in progress; onto fa0ab51
# You are currently editing a commit during a rebase.
#
# Changes to be committed:
#       new file:   fist_file
#       new file:   second_file
#

这里显示了这两次commit的message,此时随你喜欢将两次message保留也好,自己重新写也好。同样:wq保存,即可将两次提交合并。

因为最新提交在最下面,所以,该picks的提交会与上一提交合并,如果是连续修改pick,则可以将多个提交合并起来。所以如果遇到这样的报错

Cannot 'squash' without a previous commit

原因就是修改了第一行的pick,因为之上是没有commit的,所以会报错。一旦遇到这个问题,执行

rm -fr "[REPO PATH]/.git/rebase-merge"

后重新操作即可。

因此,执行git rebase命令进行提交合并的时候,指定的commit的ID必须是本次合并相关的commit的上个commit,而不仅仅是被合并commit的上个commit。