Disable backing out merges?

Angel Ezquerra angel.ezquerra at gmail.com
Fri Oct 7 01:30:53 CDT 2011


On Fri, Oct 7, 2011 at 12:26 AM, Matt Mackall <mpm at selenic.com> wrote:
> On Thu, 2011-10-06 at 23:51 +0200, Angel Ezquerra wrote:
>> On Thu, Oct 6, 2011 at 11:03 PM, Matt Mackall <mpm at selenic.com> wrote:
>> > On Thu, 2011-10-06 at 22:51 +0200, Angel Ezquerra wrote:
>> >> On Thu, Oct 6, 2011 at 9:45 PM, Matt Mackall <mpm at selenic.com> wrote:
>> >> > Seems a bunch of people are trying to use backout to deal with broken
>> >> > merges. That doesn't work:
>> >> >
>> >> > - it's not well-defined what the result should be
>> >> > - we can't actually erase the problematic DAG edge
>> >> >
>> >> > So it seems like we should just refuse to do it until we get a lot
>> >> > smarter here.
>> >>
>> >> Say I have made a merge and pushed it. Later I realize that it is a
>> >> bad merge and I want to get rid of it.
>> >>
>> >> If it is not possible to back it out. What are the alternatives?
>> >
>> > If your problem is that "I did a merge when I shouldn't have" or "I
>> > should never merge branch X and Y and I did it anyway", backout doesn't
>> > really help you with your biggest problem: you've introduced a merge
>> > into the history graph that shouldn't be there. This bogus piece of the
>> > graph will confuse future merges and the only way to truly fix it is to
>> > destructively strip the bad merge from history and all clones. Backout
>> > can't help you at all here, nor can anything else.
>> >
>> > On the other hand, if you've incorrectly performed an otherwise
>> > reasonable merge, backout is still completely the wrong tool for the
>> > job. Backout undoes all the changes in a changeset, which is not what's
>> > wanted with a valid merge.
>> >
>> > So backout on a merge is ALWAYS the wrong thing.
>>
>> Let's say that I don't really mind having the wrong merge on my
>> history, as long as nobody bases their work on it. What is the best
>> strategy in that case?
>
> Is this the second case?
>
> Here we have:
>
> o-o-o-o-o-o-o-B  <- bad merge
>  \           X
>  o-o-o-o-o-o-G  <- good merge
>
> Now you do a dummy merge:
>
> o-o-o-o-o-o-o-B
>  \           X \
>  o-o-o-o-o-o-G-G'
>
> Where you get into trouble is if B is ever chosen in the future as a
> merge ancestor, it can -reintroduce- all the broken merge decisions. And
> this can happen if anyone made commits descending from B. Consider this:
>
> o-o-o-o-o-o-o-B-a-a-a-a-a--M2
>  \           X \           /
>  o-o-o-o-o-o-G-G'-o-M1-o-o
>               \    /
>                b--b
>
> Now M1 was perfectly valid. But it creates a problem: there are two
> reasonable choices for the common ancestor for the M2 merge: B or G.
> Which one is chosen depends on which is furthest from the root. In this
> case, they're equidistant. So you'll "randomly" get either a valid or
> bogus merge.
>
> What this means in practice is if you don't discover the bad merge
> immediately (ie before you've even pushed it), then you've got to force
> everyone to stop working and migrate all their work off the bad branch.

OK, thank you for the explanation. It seems that the main problem is
that there is no way to warn users that a given changeset should not
not be built upon, once said changeset has been pushed.

> And again: backout is NOT the right tool here at all. Backout is
> supposed to undo a changeset, by definition. And that means everything a
> changeset did. And you do not want to backout an entire merge, because
> then you get this:
>
> o-o-x-xy-x  <- From bad to worse!
>   \ /
>    y
>
> In other words, you just turned a broken real merge into a dummy merge,
> which is probably not what you wanted.

OK, what you mean in that case is that "y" is lost? Now I understand
why you say that backout is not a solution.

So if backout is not a solution, and given that modifying history is
not always easy or feasible, what can we do?

Maybe what we need is not a way to fix a broken merge but a way to
tell users and mercurial that they should not _use_ that broken merge?

In one of my previous emails I proposed "closing" the invalid branch.
It is not really a good solution but it was meant as a way to signal
other users that a given revision should not be built upon.

Perhaps a better solution would be to add a mechanism to mark or "tag"
a given revision as "invalid". The regular mercurial tag mechanism (or
similar) could be used, where you could push these invalid tags as you
push regular tags. People would get these "invalid tags" when pulling.
Then mercurial could warn you if you tried to push revisions built on
top of an "invalid" revision. Mercurial could also use that
information when looking for common ancestors during a merge.

Angel


More information about the Mercurial-devel mailing list