重新排序提交

我目前正在处理一个分支,希望将一些提交合并到其他分支中:

    a-b-c-d-e-f-g (branchA)
/
--o-x-x-x-x-x-x-x-x-x-x (master)
\
x-x-x-x-x (branchB)

(字母表示提交,“ x”表示不相关的提交。)

然而,我注意到将一些提交集中起来是一个好主意。我想“连接”提交 a、 d、 e 和 g 到一个补丁中,并将其提交给 master。提交 b 和 f 应该作为一个提交到分支 B。有没有一个好的“笨蛋”式的方法来实现它?

118264 次浏览

git rebase --interactive是您需要的命令。

例如:

目前的状况是这样的:

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git status
On branch master
nothing to commit, working tree clean
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
a6e3c6a (HEAD -> master) Fourth commit
9a24b81 Third commit
7bdfb68 Second commit
186d1e0 First commit

我想重新排序提交 9a24b81(第三次提交)和 7bdfb68(第二次提交)。为此,我首先找到提交 在第一次提交之前,我们想要改变。这是提交 186d1e0(第一次提交)。

在本例中,要执行的命令是 git rebase --interactive COMMIT-BEFORE-FIRST-COMMIT-WE-WANT-TO-CHANGE:

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git rebase --interactive 186d1e0

这将在默认编辑器中打开一个文件,其内容如下:

pick 7bdfb68 Second commit
pick 9a24b81 Third commit
pick a6e3c6a Fourth commit


# Rebase 186d1e0..a6e3c6a onto 186d1e0 (3 commands)
#
# 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
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#

请注意,文件中提交的顺序与 git 日志中使用的顺序相反。在 git 日志中,最近的提交位于顶部。在这个文件中,最近的提交位于底部。

正如文件底部的注释解释的那样,我可以做很多事情,比如压缩、删除和重新排序提交。为了重新排序提交,我编辑了这个文件,使它看起来像这样(底部的注释没有显示) :

pick 9a24b81 Third commit
pick 7bdfb68 Second commit
pick a6e3c6a Fourth commit

每行开头的 pick命令意味着“使用(即包含)这个提交”,当我保存包含 rebase 命令的文件并退出编辑器时,git 将执行这些命令并更新存储库和工作目录:

$ git rebase --interactive 186d1e0
Successfully rebased and updated refs/heads/master.
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
ba48fc9 (HEAD -> master) Fourth commit
119639c Second commit
9716581 Third commit
186d1e0 First commit

注意重写的提交历史记录。

相关网址:

Git rebase 正是您想要的。

您要查找的命令是 git rebase,特别是 -i/--interactive选项。

我假设您希望在分支 A 上保留提交 c,并且您确实希望将其他提交移动到其他分支,而不是合并,因为合并很简单。让我们从操纵分支 A 开始。

git rebase -i <SHA1 of commit a>^ branchA

^表示以前的提交,因此该命令表示使用“ a”之前的提交作为基础重新定位分支 A。Git 将为您提供此范围内的提交列表。重新排序它们,告诉 git 压制合适的:

pick c ...
pick a ...
squash d ...
squash e ...
squash g ...
pick b
squash f

现在,历史应该是这样的:

    c - [a+d+e+g] - [b+f] (branchA)
/
--o-x-x-x-x-x-x-x-x-x-x (master)

现在,让我们获取分支 B 的新压缩的提交 b + f。

git checkout branchB
git cherry-pick branchA  # cherry-pick one commit, the tip of branchA

对 master 来说 a + d + e + g 也是一样的:

git checkout master
git cherry-pick branchA^

最后,更新 Branch A,使其指向 c:

git branch -f branchA branchA^^

我们现在应该:

    c (branch A) - [a+d+e+g] - [b+f] (dangling commits)
/
--o-x-x-x-x-x-x-x-x-x-x-[a+d+e+g] (master)
\
x-x-x-x-x-[b+f] (branchB)

注意,如果有多个提交要在分支之间移动,可以再次使用 rebase (非交互式) :

# create a temporary branch
git branch fromAtoB branchA
# move branchA back two commits
git branch -f branchA branchA~2
# rebase those two commits onto branchB
git rebase --onto branchB branchA fromAtoB
# merge (fast-forward) these into branchB
git checkout branchB
git merge fromAtoB
# clean up
git branch -d fromAtoB

最后,一个免责声明: 以这样的方式重新排序提交是非常有可能的,以至于一些提交不再能够干净利落地应用。这可能是因为您选择了一个错误的顺序(在提交之前放置一个补丁,引入它所修补的特性) ; 在这种情况下,您将希望中止 rebase (git rebase --abort)。否则,您将必须智能地修复冲突(就像处理合并冲突一样) ,添加修复程序,然后运行 git rebase --continue继续前进。这些指令也由冲突发生时打印的错误消息提供。

如果你想重新订购 只有最后两次提交,你可以这个 git reorder别名: https://stackoverflow.com/a/33388211/338581

git rebase -i HEAD~3

其中 3是需要重新排序的提交次数(来源)。

这将打开 Vi,列出从 最老的(顶部)到 最新的(底部)的提交。
现在 重新排序行,拯救出口编辑器。

ddp将移动当前线路 放下
ddkP将移动当前线 起来(来源)