英文:
git rebase: why do I get conflicts rebasing on top of the same state as the common ancestor?
问题
我想更好地理解我在Git中观察到的一些情况,使用git --version 2.39.2
。
在一个仓库中,我有两个长期存在的分支,默认的master
和一个从几个月前的master
分支出来的new
分支。在过去几个月里,master
上进行了一些维护工作,并偶尔将更改合并到new
分支中。另一方面,new
分支上进行了大量的工作,有许多PR合并到其中,并且在分支点之上有600多个提交。
现在,我想将new
分支重新基于master
,然后将new
合并到master
。在重新基础时,我遇到了一些小的冲突,然而这些冲突可能会破坏历史记录,因为它们会使追踪依赖版本在以前的时间点上变得更加困难。因此,我决定执行以下操作:
- 我在
master
分支上添加了一个提交,将其状态恢复到这两个分支的共同祖先。我使用了这个链接:https://stackoverflow.com/a/51906191/6760680 - 然后,我将
new
分支重新基于这个“编辑过”的master
分支,这也意味着它被重新基于远程的master
分支,以便我可以使用这个重新基于的版本来合并。
现在的问题是:为什么在执行这个过程时,我仍然遇到了一些(小的)冲突?
我在一个与这两个分支的共同祖先相同的状态上重新基础,所以我预期不会有任何冲突。我略微担心历史记录可能会因此而混乱(很难检查,正如我所说的,因为有很多提交),即使分支的最终状态是预期的。请注意,我使用了--rebase-merges
选项进行重新基础,因为我想保留合并提交,不确定是否与此有关。有没有深入了解Git的人能为我提供一些启发?
英文:
I would like to better understand something I am observing with Git, using git --version 2.39.2
.
In a repo, I have two long-lived branches, the default master
and a new
one, branched from master
several months ago. In the last months, there was some maintenance work done in master
, with occasional cherry-picking into new
. On the other hand, there was a lot of work on new
, with many PRs merged into it and more than 600 commits on top of the branching point.
I now want to rebase new
on top of master
, to then merge new
into master
. When rebasing, I had a few minor conflicts, which however risked to spoil the history, as for instance they would make it harder to track which dependency versions were used exactly back in time. I thus decided to do the following:
- I added (locally) a commit to
master
, bringing its state back to the common ancestor of the two branches. I used this: https://stackoverflow.com/a/51906191/6760680 - I then rebased
new
on top of this "edited"master
, which also implies that it's rebased on top of the remotemaster
, so I can use this rebased version to merge.
Now, the question is: why did I still get some (small) conflicts, when doing this procedure?
I was rebasing on top of a state that was identical to the common ancestor of the two branches, so I expected no conflict at all. I am slightly worried that the history might be messed up due to this (hard to check, as it's many commits, as I said), even if the final state of the branch is the expected one. Note that I rebased with the --rebase-merges
option, because I want to keep the merge commits, not sure if that can be related. Can somebody with deeper Git insights illuminate me?
答案1
得分: 1
好的,以下是已翻译的内容:
"ok..... I think your problem is the rebase itself, at least current git's implementation for rebasing merges.... even if you use --rebase-merges
and the trees involved are exactly one like the other to start with, if there is a conflict with a merge, git does not care for the trees been the same and will let you do the conflict resolution instead of using the tree of the original merge commit. We will someday tackle this in upstream but for the time being, I can offer this script:
https://github.com/eantoranz/git/blob/replay/contrib/replay
I haven't used it in a while so take it with a grain of salt... the good thing is that it doesn't move anything around.... it will print a commit ID after it has run. That commit has the rebased history, feel free to put a branch there when you are sure that branch history is what you want to have."
英文:
ok..... I think your problem is the rebase itself, at least current git's implementation for rebasing merges.... even if you use --rebase-merges
and the trees involved are exactly one like the other to start with, if there is a conflict with a merge, git does not care for the trees been the same and will let you do the conflict resolution instead of using the tree of the original merge commit. We will someday tackle this in upstream but for the time being, I can offer this script:
https://github.com/eantoranz/git/blob/replay/contrib/replay
I haven't used it in a while so take it with a grain of salt... the good thing is that it doesn't move anything around.... it will print a commit ID after it has run. That commit has the rebased history, feel free to put a branch there when you are sure that branch history is what you want to have.
答案2
得分: 0
重新基础操作比合并更复杂。合并创建一个提交,所有可能存在的冲突都在这个提交中解决。重新基础创建多个提交(所有现有的提交都被重新执行),冲突可能发生在其中任何一个。你的更改历史越复杂,你就越不应该使用重新基础,而应该使用合并。
在你(相当标准的)使用情况下,只需将“new”合并到“master”并解决所有冲突。
另一个稍微更安全的解决方案是进行两次合并:
- 将“master”合并到“new”。解决“new”中的任何冲突。
- 将“new”合并回“master”。不应该有冲突。
这种方法允许你在合并后测试“new”分支,以确保你没有在合并中破坏任何东西。
至于你的原始问题,我想你遇到小冲突的原因可能是除了你最初的分支点之外,“new”和“master”还有更多的共同祖先。我认为在长时间的开发过程中,某人将“master”合并到“new”(可能是通过某个其他分支间接完成的)。老实说,在这种情况下,我甚至不完全确定 git 是如何处理重新基础的。
英文:
Rebasing is a more complicated operation than a merge. Merge creates one commit, and all the conflicts you might have are resolved in this one commit. Rebase creates multiple commits (all of the existing commits are re-done), and conflicts might occur in any of them. The more complicated your history of changes, the less you should use rebase and the more you should use merge.
In your (pretty standard) use case simply merge new
to master
and solve all the conflicts.
Another a little more safe solution is with two merges:
- Merge
master
intonew
. Resolve any of the conflicts innew
. - Merge
new
back tomaster
. There should be no conflicts.
This approach allows you to test the new
branch after the merge to make sure you didn't break anything with the merge.
As for your original question, I suppose the reason for the small conflicts you get is that there are more common ancestors of new
and master
apart from your original branching point. I think someone merged master
into new
(probably indirectly via some other branch`) during the long course of development. Honestly, I am not even completely sure how git is doing rebase in this situation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论