关于rebase:结合Git存储库的前两个提交?

Combine the first two commits of a Git repository?

假设您有一个包含三个提交a、b和c的历史记录:

1
A-B-C

我想将两个提交A和B合并为一个提交AB:

1
AB-C

我试过了

1
git rebase -i A

这将打开我的编辑器,其中包含以下内容:

1
2
pick e97a17b B
pick asd314f C

我把这个换成

1
2
squash e97a17b B
pick asd314f C

然后Git 1.6.0.4说:

1
Cannot 'squash' without a previous commit

有没有办法,或者这是不可能的?


使用git rebase -i --root。从Git版本1.7.12开始。

在Interactive Rebase文件中,将commit b的第二行更改为squash,并在pick处保留其他行:

1
2
3
pick f4202da A
squash bea708e B
pick a8c6abc C

这将把两个提交A和B合并为一个提交AB。

在这个答案中找到。


您尝试过:

1
git rebase -i A

如果继续使用edit而不是squash,则可以这样开始:

1
2
edit e97a17b B
pick asd314f C

然后运行

1
2
3
git reset --soft HEAD^
git commit --amend
git rebase --continue

完成。


A是初始提交,但现在您希望B是初始提交。Git提交是整棵树,而不是diff,即使它们通常是根据引入的diff来描述和查看的。

即使在A和B、B和C之间有多个提交,这个方法也可以工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout <sha1_for_B>

# reset the branch pointer to the initial commit,
# but leaving the index and working tree intact.
git reset --soft <sha1_for_A>

# amend the initial tree using the tree from 'B'
git commit --amend

# temporarily tag this new initial commit
# (or you could remember the new commit sha1 manually)
git tag tmp

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after B onto the new initial commit
git rebase --onto tmp <sha1_for_B>

# remove the temporary tag
git tag -d tmp


如果是交互式钢筋网,则必须在a之前进行,以便列表:

1
2
3
pick A
pick B
pick C

成为:

1
2
3
pick A
squash B
pick C

如果a是初始提交,在a.git认为有差异之前,您必须有一个不同的初始提交,它将处理(a和b)和(b和c)之间的差异。因此,在您的示例中,壁球不起作用。


如果你有成百上千的承诺,使用Kostmo的答案

1
git rebase -i --root

可能不切实际且缓慢,这仅仅是因为REBASE脚本必须处理两次的大量提交、一次生成交互式的REBASE编辑器列表(在该列表中,您为每个提交选择要采取的操作),以及一次实际执行提交的重新应用。

这里有一个替代的解决方案,它可以避免在一开始不使用交互式钢筋时生成交互式钢筋网编辑器列表的时间成本。这样,它就类似于查尔斯·贝利的解决方案。您只需从第二个提交创建一个孤立分支,然后在其上重新设置所有子提交:

1
2
3
git checkout --orphan orphan <second-commit-sha>
git commit -m"Enter a commit message for the new root commit"
git rebase --onto orphan <second-commit-sha> master

文档

  • Git签出(1)手册页
  • Git Rebase(1)手册页

在一个相关的问题中,我设法想出了一种不同的方法来满足第一次提交的需要,也就是说,让它成为第二次提交。

如果你感兴趣的话:git:如何插入一个commit作为第一个,转移所有其他的commit?


班长:git rebase-i head~[提交次数]

假设您有以下Git提交历史记录:

pick 5152061专长:增加了对保存图像的支持。(a)选择39c5a04修复:错误修复。(b)选择839C6B3修复:冲突已解决。(c)

现在要将A和B挤压到AB,请执行以下步骤:

pick 5152061专长:增加了对保存图像的支持。(a)s 39c5a04修复:错误修复。(b)选择839C6B3修复:冲突已解决。(c)

注意:对于挤压提交,我们可以使用squash或s。最终结果将是:pick 5152061专长:增加了对保存图像的支持。(ab)选择839C6B3修复:冲突已解决。(c)


你必须执行一点命令行魔法。

1
2
3
4
5
git checkout -b a A
git checkout B <files>
git commit --amend
git checkout master
git rebase a

这应该会给你留下一个有AB和C作为承诺的分支。