修复冲突后 git 变基



有时我在变基和修复冲突后会遇到这个问题。 我做了git add .,我会跑git rebase --continue.

但是,我有时会收到此消息

Applying: xxxxxx
No changes - did you forget to use 'git add'?
If there is nothing left to stage, chances are that something else  
already introduced the same changes; you might want to skip this patch.

我一直不明白为什么会这样。所以,我最终只是做了git rebase --skip继续。谁能告诉我为什么 Git 没有意识到我解决了冲突?

与其说Git 没有意识到你已经修复了冲突,不如说 Git 的作者认为这是一个很好的安全设备。

当您正在挑选提交时会发生这种情况——请记住,git rebase,无论是有效还是实际上,都只是大量重复的挑选——这种更改与您重新定位的提交中已有的更改不完全相同,但非常相似

例如,假设原始作品是这样的:

...--o--*           <-- origin/develop

A--B--C   <-- develop

这里ABC是你所做的三个提交。 提交*develop刚开始时所处的位置,origin/develop仍然记得它。

在提交A中,修复了文件a中的某些内容,并更新了README.txt文件。 在B中,您修复了文件b中的某些内容,但忘记更新README.txt。 在提交C中,您记得更新README.txt以便执行此操作。

现在其他人已经进行了更改并将其推送到您的上游服务器,因此您可以git fetch他们的工作:

...--o--*--D--E     <-- origin/develop

A--B--C   <-- develop

然后继续git rebase你的develop在新origin/develop上。 一般来说,这将复制AB,并C到新的提交A'B'C',这样,如果一切顺利,你最终会得到:

...--o--*--D--E            <-- origin/develop
     
     A'-B'-C'   <-- develop

A--B--C        [abandoned]

新的A'-B'-C'提交只是原始git cherry-pick副本。

Git 足够聪明,如果您的提交A引入了与DE中完全相同的更改,Git 将在复制时简单地删除A:它会跳过它并仅BC复制。 但是假设A在这个意义上"等于"D,或者——让我们为了论证而说第二种情况是正确的——A是完全独立的,并且可以很好地复制。 但是,"等于"E既不是B也不是C,而是总和,B+C,"等于"E。 也就是说,您和他们进行了相同的修复,但他们记得在一次提交中修复README.txt......并且他们对文件b的更改存在一些细微的拼写差异 - 或者可能是文件b被重新格式化或其他什么,使 Git 无法按原样应用您的更改。

你手动进入并解决 Git 抱怨的b,而 Git 试图挑选提交B来制作B'。 然后git add解析的文件。 但是现在您的文件b与上游b完全匹配。 虽然这是故意的——毕竟没有什么可做b的——但 Git不知道你已经验证了这一点。 Git 认为也许你只是跑git checkout HEAD -- b看看他们的版本是什么。 这将提取他们的b并假装一切都已解决,并使您处于相同的情况。1

因此,由于这会完全放弃您的提交B,Git 会给您此警告。 如果正确的做法现在完全放弃提交B,那么毕竟您应该运行git rebase --skip,并跳过B

Git 现在将尝试应用您的C来修复README.txt。 这将不需要做任何事情,因为他们已经在他们的提交D中这样做了。 你的 Git 将再次看到,在解决冲突(甚至可能是自动的,这次)冲突后,没有什么可提交的。 Git 会想知道它是否弄错了,并让你运行git rebase --skip以确认这是正确的。

完成后,事实证明只需要复制A,实际上最终会得到:

...--o--*--D--E       <-- origin/develop
     
     A'    <-- develop

A--B--C   [abandoned]

但是 Git 希望真正确保从复制中省略BC是正确的,因为在运行git rebase --continue时相对容易忘记git add


1如果您意识到 Git 很早就没有一个好的内置git cherry-pick命令,这可能更有意义。相反,变基将提交变成补丁,然后尝试应用补丁,就好像有人把它邮寄给你一样。 然后,Git 将无法判断您是否完全忘记应用补丁。

最新更新