Mercurial 合并选择了错误的更改,解决此问题的正确方法是什么?

发布于 2024-09-28 07:31:09 字数 698 浏览 3 评论 0原文

对 .vcproj 进行了更改以修复构建计算机上的问题(变更集 1700)。后来,一名开发人员将他的更改(更改 1710 到 1715)合并到主干中,但是善变的自动合并覆盖了 1700 中的更改。我认为发生这种情况是因为他选择了错误的分支作为合并的“父分支”(请参阅​​第问题2)。

1) 解决此问题的“正确”多变方法是什么,考虑到在所有合并的文件中,只有一个文件合并不正确,以及

2) 开发人员应该采取哪些不同的措施来确保不会发生这种情况?我们有什么方法可以强制执行“正确”的方式吗?

编辑:我可能不太清楚发生了什么。开发人员 A 修改了 .vcproj 文件中的一行,删除了编译器的选项。他的签入变成了变更集 1700。开发人员 B 在前一个父级(假设变更集 1690)工作,对项目的完全不同部分进行了一些更改,但他确实接触了 .vcproj 文件(只是与开发人员 A 所做的更改相差甚远)。当开发人员 B 合并他的更改(更改为 1710 到 1715)时,合并过程会覆盖 1700 中的更改。

为了解决此问题,我只需重新修改 .vcproj 文件以再次包含更改,然后将其签入。我只是想了解为什么 Mercurial 认为它不应该保留 1700 中的更改,以及是否有“官方”方法来解决此问题。

编辑第二个:开发人员 B 发誓 Mercurial 合并了 .vcproj 文件,但没有提示他解决冲突,但当然有可能他只是记错了,在这种情况下,整个练习都是学术性的。

Changes were made to our .vcproj to fix an issue on the build machine (changeset 1700). Later, a developer merged his changes (changes 1710 through 1715) into the trunk, but the mercurial auto-merge overwrote the changes from 1700. I assume this happened because he chose the wrong branch as the "parent" of the merge (see part 2 of the question).

1) What is the "correct" mercurial way to fix this issue, considering out of all the merged files, only one file was merged incorrectly, and

2) what should the developer have done differently in order to make sure this didn't occur? Are there ways we can enforce the "correct" way?

Edit: I probably wasn't clear enough on what happened. Developer A modified a line in our .vcproj file that removed an option for the compiler. His check-in became changeset 1700. Developer B, working from a previous parent (let's say changeset 1690), made some changes to completely different parts of the project, but he did touch the .vcproj file (just not anywhere near the changes made by Developer A). When Developer B merged his changes (becoming changes 1710 through 1715), the merge process overwrote the changes from 1700.

To fix this, I just re-modified the .vcproj file to include the change again, and checked it in. I just wanted to know why Mercurial thought that it shouldn't keep the changes in 1700, and whether or not there was an "official" way to fix this.

Edit the second: Developer B swears up and down that Mercurial merged the .vcproj file without prompting him for conflict resolution, but it is of course possible that he's just misremembering, in which case this whole exercise is academic.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

活泼老夫 2024-10-05 07:31:09

我将首先解决您问题的第二部分......

如果存在冲突,自动合并工具应该迫使程序员决定合并如何发生。但一般的假设是冲突将涉及对同一组行的两次编辑。如果由于对彼此不靠近的行的编辑而产生冲突,自动合并将愉快地选择这两个编辑,并且会出现错误。

合并工具始终正确合并的一般情况很难解决,而且当前的技术确实无法解决。下面是我在 C 语言中的意思的一个例子:

int i;  // Someone replaces this with 'short i' in one changeset stating
        // that a short is more efficient.

// ...  lots of code;

// Someone else replaces all the 65000s with 100000s in another changeset,
// saying that more precision is needed.
for (i = 0; i < 65000; ++i) {
    integral_approximation_piece(start + i/65000.0, end + (i + 1) / 65000.0);
}

没有任何合并工具能够捕获这种冲突。该工具必须实际编译代码才能看到代码的这两部分彼此有什么关系,虽然在这种情况下这可能就足够了,但我可以构建一个需要运行代码的示例,并且检查结果以发现冲突。

这意味着您真正应该做的是在合并之后严格测试您的代码,就像在任何其他更改之后一样。绝大多数合并将导致开发人员必须解决的明显冲突(即使该解决方案通常相当明显),或者将干净地合并。但是,极少数不适合任一类别的合并无法轻松地以自动化方式处理。

这也可以通过鼓励本地化的开发实践来解决。例如,一个编码标准规定“变量应该在它们使用的地方附近声明”。

我猜测 .vcproj 文件特别容易出现此问题,因为开发人员不能很好地理解它们,因此如果确实出现冲突,他们将不确定如何处理它们。我的猜测是,这种情况发生了,您的开发人员只是恢复了他签入的修订版本。

至于第 1 部分……

在这种情况下该怎么做很大程度上取决于您的开发过程。您可以删除合并变更集并重做它,尽管如果很多人已经拉取了它,那么这不会很好地工作,并且如果已经签入了许多基于基于的变更集,那么它的工作效果会特别差。在合并变更集上。

您还可以签入修复合并问题的新更改。

这些基本上是你的两个选择。

在我看来,您帖子的语气表明您的组织中可能存在一些围绕此问题的政治观点,人们将此错误归咎于 Mercurial 的频繁合并。所以我会指出任何变更控制系统都可能存在这个问题。例如,就 Subversion 而言,每当开发人员在其工作目录中存在未完成的更改时进行更新时,他们都会进行合并,并且任何合并都可能会出现此类问题。

I will address the 2nd part of you question first...

If there is a conflict, the automated merge tools should force the programmer to decide how the merge happens. But the general assumption is that a conflict will involve two edits to the same set of lines. If somehow a conflict arises because of edits to lines that are not close to each other the automated merge will blithely choose both of the edits and a bug will appear.

The general case of a merge tool always merging properly is very hard to solve, and really can't be with current technology. Here is an example of what I mean from C:

int i;  // Someone replaces this with 'short i' in one changeset stating
        // that a short is more efficient.

// ...  lots of code;

// Someone else replaces all the 65000s with 100000s in another changeset,
// saying that more precision is needed.
for (i = 0; i < 65000; ++i) {
    integral_approximation_piece(start + i/65000.0, end + (i + 1) / 65000.0);
}

No merge tool is going to catch this kind of conflict. The tool would have to actually compile the code to see that those two parts of the code have anything to do with eachother, and while that would likely be enough in this case, I can construct an example that would require the code to be run and the results examined to catch the conflict.

This means that what you really ought to do is rigorously test your code after a merge, just like you should after any other change. The vast majority of merges will result in obvious conflicts that a developer will have to resolve (even though that resolution is often fairly obvious), or will merge cleanly. But the very few merges that don't fit either category can't easily be handled in an automated fashion.

This can also be fixed by development practices that encourage locality. For example a coding standard that states "Variables should be declared near where they're used.".

I'm guessing that .vcproj files are particularly prone to this problem since they are not well understood by developers and so if conflicts do appear they will not be sure what to do with them. My guess is that this happened and your developer simply did a revert back to the revision (s)he checked in.

As for part 1...

What to do in this case depends a lot on your development process. You can either strip the merge changeset out and redo it, though that won't work very well if lots of people have already pulled it, and it will work especially poorly if there are lots of changesets that have already been checked in that are based on the merge changeset.

You can also check in a new change that fixes the problem with the merge.

Those are basically your two options.

The tone of your post seems to me to indicate that you may have some politics surrounding this issue in your organization, and people are blaming this error on the frequent merges of Mercurial. So I will point out that any change control system can have this problem. In the case of Subversion, for example, every time a developer does an update while they have outstanding changes in their working directory, they are doing a merge, and this kind of problem can arise with any merge.

忘年祭陌 2024-10-05 07:31:09

在 Mercurial 中,合并没有单个父级,根据定义,它有两个且只有两个父级。当有人合并时,他们会做出两个选择:

  1. 哪两个变更集将构成这两个变更
  2. 这些变更集中哪个将是左父级,哪个将是右父级

在这两个问题中,第一个问题非常重要,第二个问题非常重要根本不重要,尽管我花了一段时间才明白这一点。

您可以使用 hg update X 选择左父级。这会更改 hgparents 的输出(或在较新版本中的 hgsummary),并本质上确定合并之前工作目录中的内容。

您可以使用 hg merge Y 选择右父项。这就是说将 X(工作目录的父目录)与变更集 Y 合并。作为一种特殊情况,如果您的存储库中只有两个头,并且您的父目录已经是其中之一,那么 Y 将默认为另一个。

我必须查看结果图才能知道开发人员做了什么,但他有可能在调用合并之前没有更新到一个头或另一个头,这将使他将一个头与历史上的某个点合并。

如果您的开发人员为合并选择了正确的父级,那么左与右并不重要——唯一真正的区别是当使用 hg diffhg log -p< /code> 或其他显示合并变更集补丁的命令,它是相对于左父级显示的。然而,这主要只是显示方面的一个因素。从功能上来说,它们几乎相同。

假设您的开发人员选择了正确的变更集,那么他应该做的是在提交之前测试合并的结果。合并软件开发,不是恼人的 VCS 副作用,并且在提交之前不进行测试就是错误。

修复

要修复此问题,只需重新正确进行合并即可。使用 hg update 设置一个父级,使用 hg merge 选择另一个。确保您当前的工作目录正确,然后提交。您可以使用 hg strip 或更好的东西摆脱他的错误合并,只需在更新后使用 hg commit --close-branch 关闭他的分支即可。

避免

你说“mercurial auto-merge”,但mercurial并没有真正自动合并。它会执行预合并,这是对明显更改的极其谨慎的组合,但它非常小心,如果每个合并父级在同一区域中添加代码,它甚至不会为您合并,因为它不知道是哪个您希望首先拥有的代码块。

您可以使用合并工具配置选项完全或逐个文件地禁用此预合并:

https://www.mercurial-scm.org/wiki/MergeToolConfiguration?highlight=premerge

In mercurial a merge doesn't have a single parent, it by definition has two and only two parents. When someone is merging they're making two choices:

  1. What two changesets will constitute the two changes
  2. Which of those changesets will be the left-parent and which will be the right-parent

Of those two questions the first is very important, and the second barely matters at all, though it took me a while to come to understand that.

You select the left-parent by using hg update X. That changes the output of hg parents (or in newer versions hg summary) and essentially determines what's in your working directory before the merge.

You select the right-parent by using hg merge Y. That says merge X (the working directory's parent) with changeset Y. As a special case, if there are only two heads in your repository and your parent is already one of them then Y will default to the the other.

I'd have to see your resulting graph to know just what the developer did, but it's possible he didn't update to one head or another before invoking merge, which would have him merging one head with some point back in history.

If your developer picked the right parents for the merge then the left vs. right doesn't much matter -- the only real difference is that when one uses hg diff or hg log -p or some other command that shows the patch for a merge changeset, it's displayed relative to the left-parent. That's, however, mostly a factor in display only. Functionally they're pretty much identical.

Assuming your developer picked the right changesets then what he should have done was test the result of the merge before committing it. Merging is software development, not an annoying VCS side effect, and not testing before committing is the error.

Fixing

To fix this, just re-do the merge correctly. Use hg update to set one parent, use hg merge to pick the other. Make sure your current working directory is correct and then commit. You can get rid of his bad merge using something like hg strip or better, just close down his branch with hg commit --close-branch after updating to it.

Avoiding

You say "mercurial auto-merge", but mercurial doesn't really auto-merge. It does a premerge which is an extremely cautious combination of obvious changes, but it's so careful it won't even merge for you if each merge parent adds code in the same region because it can't know which block of code you'd rather have first.

You can disable this premerge entirely or on a file-by-file basis using the merge tool configuration options:

https://www.mercurial-scm.org/wiki/MergeToolConfiguration?highlight=premerge

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文