gnu-arch-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gnu-arch-users] Re: --skip-present implemented


From: Tom Lord
Subject: Re: [Gnu-arch-users] Re: --skip-present implemented
Date: Wed, 10 Sep 2003 08:46:40 -0700 (PDT)

    > From: John Goerzen <address@hidden>

    > Miles Bader <address@hidden> writes:

    > > I do `pure merges' from my auxilarly branches to my main branch, and
    > > then later want to just do a normal merge from the main branch to the
    > > aux branches, but star-merge always gets completely confused by the
    > > previous pure merges (and of course replay just gets conflicts).
    > > Now I can just do replay --skip-present to do the main->aux merges!

    > Can somebody explain to a tla newbie *why* star-merge gets confused
    > and how to fix it?  It seemed to me from reading the tutorial that
    > this is exactly the situation star-merge was supposed to fix.

"pure merges" == "cherry picking", in this case.

If you draw lists of revisions in two branches, along with the merge
arrows between them:

       main:                    branch:

        patch-p <------         patch-A
        patch-q -----  `------- patch-B
        patch-r      \          patch-C
        patch-s       \         patch-D
                       `------> patch-E

("everything up to branch--patch-B was merged into main at patch-p"
and "everything up to main--patch-q was merged into branch at
patch-E")

then star-merge works when the most recent line doesn't cross another.
For example, to merge everything up branch--patch-E into main to make
patch-t, it's:

        delta(main--patch-q, branch--patch-E)[main-patch-s]

("apply the diffs from patch-q to patch-E to a patch-s tree").


But, now suppose that Miles instead picks branch--patch-C to make
main--patch-t, then the situation is like:


       main:                    branch:

        patch-p <------         patch-A
        patch-q -----  `------- patch-B
        patch-r     ,---------- patch-C
        patch-s    /  \         patch-D
        patch-t <-'    `------> patch-E
                                patch-F

The most recent merge lines cross.

How does one make a main--patch-s which is fully-up-to-date with
branch--patch-F?  Clearly, the changes in patch-D and patch-F have to
be applied.  A subtlety is that there _may_ be changes in patch-E,
other than the merge from main, and those should be picked up as well.

Absent (literal) magic or true artificial intellegence, the merge to
make patch-s can not be automated in a way that certainly avoids
spurious conflicts.  star-merge will do it's best in this case, but
the changes from patch-q that werer merged into patch-E will show up
as conflicts since no tool can reliably separate out those changes
from others that may have occured in patch-E.

One issue is that star-merge should probably have a --forward option.
That would actually eliminate many spurious conflicts in cases like
this.

However, there is another option.  Instead of trying to write an
artificial intellegence program to deal with the problems of patch-E,
we can use Miles.  Miles can assert "I know that there are no `other'
changes in patch-E.  If your tree has any of the patches that were
merged in at patch-E, that's as good as having patch-E itself."

That assertion is what --skip-present is for.    So, miles can make
patch-s with something like:

        % tla get main--patch-t wd
        % cd wd
        % tla whats-missing --skip-present branch
        patch-D
        patch-F

Note that even though patch-t doesn't have patch-E, it doesn't appear
in the output of whats-missing with --skip-present.   That's because
patch-E merged in patch-q and the patch-t tree _does_ have patch-q:
which --skip-present says "is as good as having patch-E itself".


So:

        % tla whats-missing --full --skip-present branch \
          | tla replay --exact --list -

        [applies patch-D, applies patch-F]

        % tla commit 

the result is:

       main:                    branch:

        patch-p <------         patch-A
        patch-q -----  `------- patch-B
        patch-r     ,---------- patch-C
        patch-s    /  \         patch-D
        patch-t <-'    `------> patch-E
        patch-s <-------------- patch-F

and notice that the most recent merge arrow doesn't cross any other.

So now, if we later have:


       main:                    branch:

        patch-p <------         patch-A
        patch-q -----  `------- patch-B
        patch-r     ,---------- patch-C
        patch-s    /  \         patch-D
        patch-t <-'    `------> patch-E
        patch-s <-------------- patch-F
        patch-t                 patch-G
        patch-u                 patch-H

star-merge is happy again.  A merge of main into branch is:

        delta(patch-F,patch-u)[patch-H]

and a merge of branch into main is:

        delta(patch-F,patch-H)[patch-u]


If all you ever use with branches in a "hub and spokes" arrangement is
star-merge between the hub and the spokes, then star-merge is always
happy.  When you start merging in using other merge techniques,
star-merge can become unhappy -- but you can make it happy again by
drawing diagrams like the above and figuring out what you want to do
to restore the "merge line doesn't cross" property.


Hope I got the math right :-)
-t





reply via email to

[Prev in Thread] Current Thread [Next in Thread]