noob - understanding branches diverged

Stephen J. Turnbull stephen at xemacs.org
Sat Apr 18 07:23:44 BST 2009


Mike Mattie writes:

 > That does click. The merge did indeed work for me but it hosed the
 > assumptions that my Emacs interface was based on.

Ah.  Indeed, Emacs can be like an autistic child, refusing to accept
change but showing more than a touch of genius in how it handles the
familiar routine.

 > As long as the resolution of conflicts in a merge shows up as
 > commit/delta distinct from the changes pulled that caused a conflict

[[ To see how all the following fits together, run the attached script
(untested, it's cleaned-up shell history output, but should work).  Of
course you need git installed but it only needs to be recent enough to
include gitk.  Then you can browse the changes described in gitk. ]]

I think everybody wants this property, and the Darcs people have made
a cult out of supporting it, with whole research papers full of voodoo
math analyzing "catches", "conflictors", and other cosmological
virtual particles.  But IMHO it's not really coherent.  Graphically,
we can show things like this (the "straight" branch is the mainline,
the other is the branch):

                    0 ---> 1 ---> 2 ---> 4 ---> 5
                             \         /
                              `-> 3 --'

Where 0 -> 1 is "ancient history", 1 -> 2 +3 is the "branch event",
2 + 3 -> 4 is the "conflicted merge", and 4 -> 5 is the "conflict
resolution patch".  But this is not really coherent, because version 4
is not a program, so arguably not a "real version"!  Considered as
text, containing textual conflict markers (<<<<<<<,=======,>>>>>>>),
OK, you have a version, but in fact it contains exactly the same
information as the three versions 1, 2, and 3 combined (yes, this is
obvious but it made me nervous too ;-).  And as you know ediff and
emerge can represent that information in a very dynamic and convenient
way.  Do you need version 4 for this?

Now let's look at the resolution patch.  So do "diff -r 4 -r 5".  What
do you learn from that?  Then do a git combined diff (git diff --cc),
which compares 2, 3, and 5.  Do you really need version 4 at all?  You
can't build the project with it, and all the contained information is
available algorithmically.  (So algorithmically that it's embedded in
git-re-re-re.)  In my opinion, the best way to represent the situation
is as a commit whose content is a program (well, it might be buggy, so
"intended to be" a program), with multiple parents being the recent
tips of the branches being merge.

Now, it might be that your Emacs interface would be happier with
having 4 around in the short run.  But I would worry that it will be
more confusion than it's worth in the long run.

 > cherry picking from diverged branches will not be degraded from the
 > "not diverged" case.

I'm really not sure what this means, though.  I think you simply need
to be able to identify 2 and 3 as the individual parents of 4, and
then you can skip 4 and go directly to 5' (ie, the same content as 5
but with 4's parents, so it needs a different "name").

fun-with-foo.sh:

#!/bin/sh
# "rev N" refers to the graph in the email.

pushd /tmp
mkdir foo
cd foo
git init
# We're at rev 0.

echo foo > foo
git add foo
git commit -m foo foo
# We're at rev 1.

git branch branch
echo bar >> foo
git commit -m bar foo
# We're at rev 2.

git checkout branch
# We're back at rev 1, but the next commit will be to 'branch'

echo baz >> foo
git commit -m baz foo
# We're at rev 3.

git checkout master
# We're back at rev 2.

git merge branch
# Oops!  But just commit it as is.
git add foo
git commit -m merge-with-conflicts
# We're at rev 4.

# Now, we decide we prefer 'quux' to 'bar' or 'baz' -- no offense intended!
# in a script it's easier to just replace the whole file
echo foo > foo
echo quux >> foo
git commit -m quux foo
# We're at rev 5.

# These stunts are done by professional drivers in special
# fortified automobiles.  Kids, don't try this at home!
echo Direct merge without resolution patch. \
| git commit-tree `git cat-file commit HEAD | grep tree | cut -b 6-` \
                  -p `git rev-parse HEAD~2` \
                  -p `git rev-parse HEAD^^2` \
                  > .git/refs/heads/implicit-resolution
# The rev just created isn't in the graph in the email,
# and HEAD is still at rev 5 in the repo.

# View the DAG, and browse the diffs.
# Especially compare the "resolution patch" shown at 'master'
# with the "combined diff" shown at 'implicit-resolution'.
gitk --all &

# end fun-with-foo.sh



More information about the bazaar mailing list