利用Git的Rebase功能合并一系列commits

工作中如果使用Git作为版本管理工具的话,应该经常会遇到因为各种原因一下提交了很多个commit的情况,比如添加一个功能,测试出问题继续commit修改,最后git log看提交历史就会变成这样:

# git log
commit 9995aafb7a597d9a7fcf9a341a731324813c5aad (HEAD -> master)
...
    Commit 4

commit 54062e7317fa19a228d8f4f63236467317c17672
...
    Commit 3

commit 1571ee6b861315ec46875fbececd46c9daaa5d04
...
    Commit 2

commit ae95aac116af934742e1dd2eca435a0d6e70b77f
...
    Commit 1

commit 3f0373c3afb9e9ffd6174b8244ec3e936d3583e0
...
    init

这样看起来不那么美观,也会一定程度上污染主分支,如果遇到问题,需要看diff的时候,也会不那么方便,所以介绍一个利用git rebase命令合并一系列commit的方法。

首先,需要确定要合并哪些commits,以上面的例子,假设我们需要合并Commit 1Commit 4这几个提交,那么,我们就要找到这几个提交的上一个提交的CommitID,也就是3f0373c3afb9e9ffd6174b8244ec3e936d3583e0

然后,我们执行git rebase -i 3f0373c3afb9e9ffd6174b8244ec3e936d3583e0,此时会弹出编辑器,让你选择针对这些提交做那些操作:

pick ae95aac Commit 1
pick 1571ee6 Commit 2
pick 54062e7 Commit 3
pick 9995aaf Commit 4

# Rebase 3f0373c..9995aaf onto 3f0373c (4 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
# b, break = stop here (continue rebase later with 'git rebase --continue')
# 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.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

可以看到最上面的4行,是需要执行的操作,在底下也有注释,每个提交前面的命令代表的含义,我们要用的命令是squash,即合并到前一个提交中去,当然也可以根据情况改成其他,这里就不说明了。

我们要做的是合并这几个提交,那就需要把需要合并的都替换成squash,像这样:

pick ae95aac Commit 1
squash 1571ee6 Commit 2
squash 54062e7 Commit 3
squash 9995aaf Commit 4

然后直接保存,如果一切顺利(没有冲突)的话,会直接弹出来Commit Message的编辑器,像这样:

# This is a combination of 4 commits.
# This is the 1st commit message:

Commit 1

# This is the commit message #2:

Commit 2

# This is the commit message #3:

Commit 3

# This is the commit message #4:

Commit 4

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Wed May 22 17:25:03 2019 +0800
#
# interactive rebase in progress; onto 3f0373c
# Last commands done (4 commands done):
#    squash 54062e7 Commit 3
#    squash 9995aaf Commit 4
# No commands remaining.
# You are currently rebasing branch 'master' on '3f0373c'.
#
# Changes to be committed:
#       modified:   README

可以看到几个commit message都在一起了,可以选择保留,也可以选择重新编辑,这里就都保留着,直接保存,就rebase成功了,再git log看一下,是不是变的清爽了?

# git log
commit 1cf7ca9baabf811573e3d46e8a1c33353d044fcd (HEAD -> master)
...
    Commit 1

    Commit 2

    Commit 3

    Commit 4

commit 3f0373c3afb9e9ffd6174b8244ec3e936d3583e0
...

    init