Git Rebase 的两个应用场景

发布于 2024-07-26  107 次阅读


  在本章中我们将介绍常见的git rebase用法。

一、合并commit

  假设我们现在有如下的log

commit 72ff789d5a79cb0e79728bc86355c067b24a5b34 (HEAD -> master)
Author: SwordofMorning <969211735@qq.com>
Date:   Thu Jul 25 14:53:56 2024 +0800

    rebase_02

commit 0cd3a6179b7446de5e9f12e4a6cbd85c2553e959
Author: SwordofMorning <969211735@qq.com>
Date:   Thu Jul 25 14:53:33 2024 +0800

    rebase_01

commit 3bbb67450967dd8de8f6271f8f8e60119b77c3f4 (origin/master, origin/HEAD)
Author: SwordofMorning <969211735@qq.com>
Date:   Thu Jul 25 11:04:09 2024 +0800

    RV1126 05, Trick 02

commit 261762b3aeae2e52de8484424079bc3989c8ac44
Author: SwordofMorning <969211735@qq.com>

  我们希望合并两个最新的、未提交的commit,我们可以使用:

git rebase -i HEAD~2

  这里的编辑器使用vim,如果使用vscode则会遇到神秘力量,gitlens插件似乎也不支持合并commit这种rebase操作。编辑器中会出现:

pick 0cd3a61 rebase_01
pick 72ff789 rebase_02

# Rebase 3bbb674..72ff789 onto 3bbb674 (2 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.
#

  我们将其中修改为:

pick 0cd3a61 rebase_01
squash 72ff789 rebase_02

pick表示保留当前commit,squash表示将当前commit与上一个commit合并。保存之后则是合并后的commit信息:

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

rebase_01

# This is the commit message #2:

rebase_02

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Thu Jul 25 14:53:33 2024 +0800
#
# interactive rebase in progress; onto 3bbb674
# Last commands done (2 commands done):
#    pick 0cd3a61 rebase_01
#    squash 72ff789 rebase_02
# No commands remaining.
# You are currently rebasing branch 'master' on '3bbb674'.
#
# Changes to be committed:
#       new file:   rebase_01.txt
#       new file:   rebase_02.txt
#

保存之后我们可以发现最新的两个commit已经被合并了。

二、合并分支

  假设我们现在有如下的工作树:

(master)B -> A 
(dev)D -> C -> B -> A
          ↓
(master)E -> B -> A 
(dev)D -> C -> E -> B -> A

  我们在(dev)B -> A上提交了D -> C -> B;另一个人在(master)B -> A上提交了E -> B。这里我们使用rebase来合并的话,将会产生D -> C -> E -> B的线性提交记录,而不会有merge一样的交叉。下面通过具体的例子来看一下。

  下面我们在master上有一条新的commit,在dev上有两条commit,我们希望将其合并。

图1
图1:master上的修改
图2
图2:dev上的修改
图3
图3:dev 02上的修改

此时我们切换到dev分支,使用:

# 切换分支
git checkout dev
# 开始合并
git rebase master

此时我们需要处理冲突,在处理完成之后使用git status来确认是否已经没有需要继续的事项:

git status
interactive rebase in progress; onto 3369821
Last commands done (2 commands done):
   pick 6bf296f dev
   pick 68ec855 dev 02
No commands remaining.
You are currently rebasing branch 'dev' on '3369821'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   Computer Science/Academic/Git/03.md

        modified:   Computer Science/Academic/Git/03.md

此时我们还需要继续:git rebase --continue,直到git status提示我们:

nothing to commit, working tree clean

  我们可以发现,此时的工作树如下所示:

图4
图4:rebase之后的工作树

  我们切换到master上,在git merge dev之后删除dev分支,得到:

图5
图5:最终得到的分支