git 跨合并丢失提交的奥秘

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13468027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 07:46:50  来源:igfitidea点击:

The mystery of the missing commit across merges

gitgithub

提问by Saurabh Nanda

I'm having this strange problem with Git merging that I'm unable to explain or categorize. Is it a missing commit. Is it a merge gone wrong? Is it corrupted data? Here's what the repository history looks like:

我在 Git 合并时遇到了这个我无法解释或分类的奇怪问题。它是一个丢失的提交。是合并出错了吗?是否损坏了数据?这是存储库历史记录的样子:

master----\----commit A----cherry-picked changesets from topic---commit B--\----commit C----merge---
           \                                                                \              /
            topic-----------------------------------------------------------merge---------/

Now, my problem is that when masteris merged INTO the topicbranch (to bring it up-to-date with commits A & B), the changeset introducted by commit B is just not there! If commit B was modifying files foo& bar, even got lot does not show those files being changed with the merge. There isn't even any conflict in files fooand bar

现在,我的问题是,当master合并到topic分支中时(以使其与提交 A 和 B 保持同步),提交 B 引入的变更集不存在!如果提交 B 正在修改文件foo& bar,即使得到了很多也不会显示这些文件在合并时被更改。文件中甚至没有任何冲突foobar

Now when I merge topicback into master, commit B is in-effect reversed without ANY log or trace of the reversal!

现在,当我合并topic回 时master,提交 B 实际上已逆转,没有任何日志或逆转痕迹!

What could've gone wrong?

出了什么问题?

采纳答案by Jan Hudec

master----\----commit A----cherry-picked changesets from topic---commit B--\----commit C----merge---
           \                                                                \              /
            topic-----------------------------------------------------------merge---------/
                                                                            ~~~~~
                                                                              ^
                                                                              + here you merged B in topic

There is a merge already in topic that has commit B as parent. So B is fully merged in topic and won't be merged anywhere anymore.

主题中已有一个合并提交 B 作为父项。所以 B 在主题中完全合并,不会再在任何地方合并。

Since you don't have the changes in topic, you apparently reverted them on topic, either in the merge itself or in a following commit. Such reversal is a regular commit for the merge algorithm and it's not merged into master. So when you merge topic into master, this commit's changes will be merged, reverting commit B.

由于您没有更改主题,因此您显然在合并中或在随后的提交中恢复了主题。这种反转是合并算法的常规提交,它不会合并到 master 中。因此,当您将主题合并到 master 时,此提交的更改将被合并,还原提交 B。

To get the changes from B back, you have to either:

要从 B 取回更改,您必须:

  • Find and revert the reversal of B's changes on topic.
  • Cherry-pick B (git cherry-pick B) on topic.
  • Redo the merge, rebase topic after the merge on the new merge and forget the original branch, but as that involves rewinding you can only do that if you control all repositories that have the branch.
  • 查找并还原 B 对主题更改的逆转。
  • 樱桃采摘 B ( git cherry-pick B) 主题。
  • 重做合并,在新合并后重新调整主题并忘记原始分支,但由于这涉及倒带,您只能在控制具有该分支的所有存储库时才能这样做。

How the changes might have been reversed without you realizing it? If you are merging and get conflicts, you might resolve them sloppily using "local" thinking that you don't need these changes there yet. But from Git's (or any other version control system's for that matter; 3-way merge works the same in all of them) point of view you've seen the changes and rejected them, so you won't get them again, ever, unless you manually re-apply them.

在你没有意识到的情况下,这些变化是如何被逆转的?如果您正在合并并遇到冲突,您可能会使用“本地”认为您还不需要这些更改来草率地解决它们。但是从 Git(或任何其他版本控制系统)的角度来看,您已经看到了更改并拒绝了它们,因此您永远不会再次获得它们,除非您手动重新应用它们。

The conflict might have easily been caused by the earlier cherry-picks. While the algorithm won't declare conflict if both sides look the same and thus if you cherry-pick and than merge, it will declare conflict if you modify the cherry-picked code on one side. Say you have:

冲突可能很容易由早期的樱桃挑选引起。如果双方看起来相同,则算法不会声明冲突,因此如果您挑选而不是合并,它会声明冲突,如果您修改一侧挑选的代码。说你有:

----\-- A -------- B' -- B2 --\
     \                         \
      D -- B -- E -----------merge

where B'picks Band B2modifies the same code that Bdid. In that case the merge will see that one side did Band the other side did B2, because the cherry-pick is hidden by B2and will thus declare conflict between Band B2. And if you don't carefuly look at the history, you may easily resolve this wrong. You can avoid the problem if when picking a commit you carefuly merge the target branch into the source one like this:

whereB'选择BB2修改相同的代码B。在这种情况下,合并将看到一侧 doB和另一侧 do B2,因为樱桃选择被隐藏,B2因此将声明B和之间的冲突B2。如果你不仔细查看历史,你很容易解决这个错误。如果在选择提交时小心地将目标分支合并到源分支中,则可以避免该问题,如下所示:

----\-- A --------\- B' -\- B2 --\
     \             \      \       \
      D -- B -- E --m1-----m2----merge

where m1is normal merge with no cherry-pick involved and m2is resolved with local version, because it only has the cherry-picked changes on remote. That will ensure further merges will work correctly.

哪里m1是正常合并,不涉及樱桃挑选,并m2用本地版本解决,因为它只有远程挑选的更改。这将确保进一步的合并能够正常工作。

It should actually be possible to write a merge strategy for git to do this automatically.

实际上应该可以为 git 编写一个合并策略来自动执行此操作。

回答by VonC

Not sure why Bisn't there, but I would recommend rebasing topicon top of masterinstead of merging masterinto topic.

不知道为什么B是不存在的,但我会建议重订topic之上master,而不是合并mastertopic

Your cherry-picked commits are duplicated into master, and that doesn't play well when merging masterinto a branch (topic) with those same commits already present.
This is different when you rebase topicon top of master: any duplicate commit is notreplayed.

您精心挑选的提交被复制到 中master,并且在合并mastertopic已经存在相同提交的分支 ( ) 中时效果不佳。
当您topic在 基础上变基时,这是不同的master不会重播任何重复的提交。

Of course, the issue with rebase is that is changes topicSHA1, which is problematic if you had already pushed topicto an upstream repo (and other people have already pulled topic).

当然,rebase 的问题在于更改topicSHA1,如果您已经推topic送到上游存储库(并且其他人已经拉取了topic),这将是有问题的。

In general, as illustrated in "What is the right git workflow with shared feature branches?", you would want to avoid "back-merge" (masterto topic) and use mainly merges in one way only (topicto master).

通常,如“具有共享功能分支的正确 git 工作流程是什么?”中所述,您可能希望避免“反向合并”(masterto topic)并仅以一种方式主要使用合并(topicto master)。