为什么从git rebase删除的提交会导致合并冲突?

时间:2019-01-31 13:16:45

标签: git rebase merge-conflict-resolution

我的问题

我一直在做一个git repo。在发布更改之前,我想删除一些提交-a023b43315424b7b51754-因为它们没有反映任何有意义的更改。唯一重要的时间点是第一次(70f72ca)和最后(6937ddd)次提交。

我尝试了什么

git rebase -i 4c802c1

我选择:

pick 70f72ca Remove repetitions from Makefile
d a023b43 Separate target for image conversion
d 315424b Remove image conversion (#1)
d 7b51754 Fix Makefile
pick 6937ddd CV 2019.01

最终目标是创建一个如下所示的git日志:

6937ddd CV 2019.01
4c802c1 Initial commit

什么没用

Auto-merging src/Adam_Matan.tex
CONFLICT (content): Merge conflict in src/Adam_Matan.tex
error: could not apply 6937ddd... CV 2019.01

Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

Could not apply 6937ddd... CV 2019.01

据我了解,这两次提交只是我的工作目录的快照。我想要两个快照-原始提交和CV 2019.01一个。我不想以任何方式合并或合并它们。为什么会收到合并冲突消息?

我的问题

如何从分支中删除所有中间提交,而仅保留第一个和最后一个提交?

更新

压扁也会产生合并冲突:

git rebase -i 4c802c1
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
error: could not apply 315424b... Remove image conversion (#1)

3 个答案:

答案 0 :(得分:2)

问题是git rebase使用了与git整体定义提交方式相矛盾的术语。提交是快照,但是rebase将提交视为其父提交与其自身之间的补丁(一组更改)。

因此,如果您告诉rebase“删除提交”,它认为您要撤消该提交补丁所应用的更改。

如果要删除一些快照,同时保持以后的快照相同,请告诉rebasesquash提交。用rebase的术语来说,这意味着您正在将多个提交中的更改合并到最新的这些提交中。

答案 1 :(得分:1)

通过执行一系列提交并重新应用它们(可能在不同的“基础”对象上)来进行基础操作。它可以通过为每个提交创建补丁,然后重新应用它们,或者按顺序挑选它们来完成。

不管采用哪种机制,通过从基础指令列表中删除提交,您都要求将这些更改包括在内。

想象一下,如果您有一些文件,并且在其初始版本中,它只有一行包含内容one。想象一下,在下一次提交中,您将one更改为two。在随后的提交中,将twothree。然后从threefour,最后从fourfive。因此,您现在有五个提交,每个提交都会更改此行。

想象一下,在每个提交中,您都给了它一条指示内容更改的消息,神奇地,提交ID(哈希)也反映了内容。运行rebase -i --root将为您提供以下脚本:

pick 1111111 add one
pick 2222222 change one to two
pick 3333333 change two to three
pick 4444444 change three to four
pick 5555555 change four to five

换句话说,第一次提交选择从零到one的更改。第二个选择将从onetwo的变化中进行选择,以此类推,直到最后一条指令将fourfive的变化中进行选择。

如果您删除其中一些代码行,则可以:

pick 1111111 add one
pick 5555555 change four to five

您将有两个樱桃小点心。第一个将添加内容为one的文件。第二个尝试将这些内容从four更改为five

A,这些内容不是 four。因此,您有冲突。

如果您的目标是从onefive而没有中间提交,那么您想squash或将它们标记为fixup提交。

pick 1111111 add one
pick 2222222 change one to two
squash 3333333 change two to three
squash 4444444 change three to four
squash 5555555 change four to five

在这种情况下,第一个更改将被精心挑选,因此将创建文件one。后续的更改将经过精心挑选,因此内容将从one更改为two。接下来的更改将被挑选出来,进一步更新文件,但是这些更改将被“压缩”到先前的提交中。这样,您将获得全部内容,但最终只会得到两次提交。

(如果您将它们标记为fixup个提交,您将获得相同的内容,但是它们的提交消息不会包含在建议的提交消息中。

答案 2 :(得分:-1)

在这种情况下,我必须手工制作自己的提交

  

最终目标是创建一个如下所示的git日志:
  6937ddd CV 2019.01
  4c802c1初始提交

  1. 获取第一次提交的完整SHA1。以后需要它。
    git rev-parse 70f72ca
  2. 将最后一次提交的提交对象检索到文本文件。
    git cat-file commit 6937ddd > commit.txt
  3. 编辑commit.txt。将parent的{​​{1}}行更改为7b51754....的输出
  4. 将(自定义)提交对象写入git数据库 1)
  5. 标记/分支/重置-强制使用上述命令打印出的SHA1。您应该会看到所需的历史记录。

之所以起作用,是因为您已经用当前的提交链创建了所需的仓库状态。在提交对象中,回购状态由cat commit.txt | git hash-object -t commit --stdin -w行定义,因此您在这里要做的就是显式定义哪个回购状态跟随另一个状态。