Branches in general

Eric M. Hopper hopper at omnifarious.org
Sun Jun 10 09:41:05 CDT 2007


On Sat, 2007-06-09 at 16:27 -0500, Matt Mackall wrote:

> > > > A1--A2--A3        A4------A5
> > > >          \        /       /
> > > >          B1--B2--B3--B4--B5
> > > > 
> > > > 
> > > > So, in this case, what you really did when you merged B3 is that you
> > > > said that B1->B3 are now also part of branch A.  Because Mercurial
> > > > associates one branch per revision, this is not possible to represent,
> > > > and so an artificial revision is created on branch A to represent this.
> > > 
> > > In some sense it's artificial, yes. No files are touched, etc. In some
> > > sense it's not: declaring that the changes in B3 are now part of
> > > branch A is an event. It has a time, it has an associated user, and it
> > > may have a non-trivial description.
> > 
> > Usually I don't want to know this.  I can see some cases in which it's
> > an event worthy of the world knowing about, but mostly I don't think it
> > is.
> 
> 
> You don't want to know this.. *ever*? The alternative that people are
> proposing is -no history-.


I think I don't agree with the no history approach after some thought.
But I also think that not every branch merge is deserving of being
recorded in the history.  I think this will clutter the history and may
result in poor decisions by both humans and algorithms.


> > In fact I think this sometimes can obscure important things
> 
> 
> Be specific about these "things" or this will continue to get nowhere.


In this case, it doesn't make it very clear that basically nothing was
done on branch A for quite some time while B was being merged in.  It
makes it look like there were several merges of substance when in fact
there were none.


> > Yes, for example when you grab a branch head you can get revisions with
> > branch comments stating that they're from all kinds of other random
> > branches.  They just happen to be ancestors of the head of the branch
> > you wanted.
> 
> 
> [Damnit, don't delete the context. I've just come from reading 1000+
> LKML messages and I have no idea what you're responding to any more.
> Oh, ok, this is the "heuristic that everything that's an ancestor is
> on a branch".]


*chuckle*  I'll try to be more judicious in my eliding of history.
Revision control for handling emails? If mailers were a bit more
religious about the Message-ID, In-Reply-To, and References fields you
could construction a revision DAG pretty easily.  :-)


> Uh, so? Why does this matter? Just ignore that field in the log if it
> bothers you so much - the proposed alternative (git-style) doesn't
> have this information so you should be happy. Or would you rather
> report every branch that a changeset is a member of? Possible, but
> expensive.


I think this means that I don't think that the history of which branch a
changeset was developed for is a good be-all and end-all indicator of
which branch the changeset is a part of at the moment.  I don't
necessarily think it's terribly useful to be able to ask which branches
a particular changeset is currently part of.

But, I do think that it's important than branch A's head may in fact
have been developed for branch B.  Just because it was developed for
branch B does not mean it can't be on branch A too.


> > When you create a new branch, suddenly all the changes that are
> > ancestors of it are on your new branch no matter what branch tags they
> > may have in their revisions.
> 
> 
> Which makes your working definition of "branch" (all ancestors of
> branch tips) not very interesting, IMO. Was commit 500 in the hg repo
> on the stable branch in any useful sense? Sure, it shows up in the
> stable release, but it predates the existence of the concept of the
> stable branch by a year or so.


When you want all the revisions needed to have a branch my definition is
important.  When you're looking at a particular revision and trying to
figure out why it was developed it's kinda useless.


> A related question is whether the changesets in -stable are in -main.
> Well the answer of course is yes because we merge stable into main
> regularly. We can see that by following the log of -main. It would be
> more convenient to have a command to answer this question (is x an
> ancestor of y?). But we can also answer the fairly important question:
> in what context was this patch developed?


I think storing that context in a revision is probably important.  It's
a good piece of documentation about a revision that tells you something
useful.


> People have to go out of their way to find those heads and check them
> out so I don't really consider that a problem. Nor is it terribly
> catastrophic if they do. It might be interesting to talk about ways to
> "close" old heads. Your "active" heuristic isn't bad.


I have a refinement of my idea...

Keep the branch tag in a revision.  It doesn't say which branch a
revision is on, just which revision it was developed for.  And that's a
pretty important piece of information.

But, have a list of heads that's not version controlled and possibly has
some means of being propagated from repo to repo by push, pull and
clone.  That list will give you a list of what the repo owner thinks are
active branches, and which revisions are the ones the repo owner thinks
are the heads of these branches.

Right now this information is being re-created by making some guesses
about which revisions are branch heads by looking at the history of
which revision a branch was developed for.  The addition of fast-forward
merge revisions is a kludge to make this guess give the right answer in
more cases.

I think this allows you to have localbranches without having to have a
bunch of clones laying side-by-side, and instead you have a
non-propagated version of this heads file.

You implement fast-forward merges by keeping two 'current branch' files.
The first would be a new file that would indicate a repo-wide preference
for new revisions checked in locally.  The second would be the existing
piece of dirstate information.   Commit would warn you and refuse to
commit without a special flag if the dirstate information and the
preference disagreed with eachother.  Doing a fast-forward merge would
just result in the dirstate being updated with no commit.  Commit would
also warn you and refuse to commit without a special flag if you
committed a change that consisted only of an update to the branch tag.

update, even with -C, would warn you and possibly refuse to update
without a special flag when you moved to a revision that wasn't in the
branch (by the ancestor of a head definition) you were currently
developing for.

hg tip would give you the tip for the preferred branch by default.

hg heads would give you the heads for the preferred branch by default.
It would use the heads file.  You could give it a flag to ignore this
file and use the existing algorithm.  You could also give it a flag to
ignore the preferred branch and give you repo-wide heads.

The file of heads would be updated by commit when you did a fast-forward
merge or when you committed a new change on a branch.

hg branches would only report heads that existed in the file of heads
unless you gave it a flag to report everything, in which case it would
use the file of heads in combination with the existing algorithm for
determining branch tips.  You could give it a flag that would completely
ignore the file of heads.

hg branches or hg heads might also be able to write a completely new
file of heads based on the existing algorithms.


> > And I might also miss calling something a head
> > because it doesn't have a branch tag that says it's on that branch, but
> > from the perspective of anybody who's doing development it actually is a
> > head for that branch.
> 
> Like B3? If you look at this graph:
> 
> S1-S2-S3           
>         \ 
>          F1-F2-F3  
> 
> F3 is *not* the head of S. The head of S is S3. You wouldn't want F3
> to be head because "F" here stands for "feature" and "S" stands
> for "stable". Compare:
> 
> S1-S2-S3          S4   (stable)
>         \        /
>          F1-F2-F3      (feature)
> 
> An explicit action is needed to pull the work on the feature branch
> into the stable branch. And that's a good thing.


I think it's good that an explicit action is required.  I think it's a
bad thing for a new revision to be required to record this fact in order
to make the current algorithms work for determining branch heads and
tips.


> Without per-changeset branch tags, we have:
> 
>              unrecorded
>     S     F    action             S,F
>     v     v      ->                v
> 1-2-3-4-5-6              1-2-3-4-5-6
> 
> Notice how much less information is in this last picture. Was 4
> developed on the stable branch? That information is forever lost.


I think the context information in a revision about which branch a
revision was developed for is important and useful.  But I think it's
usefulness is limited when trying to determine the heads and tips for
branches.

I propose this:


        ,-S
S1-S2-S3
        \ 
         F1-F2-F3  
                 `-F


unrecorded action


S1-S2-S3
        \ 
         F1-F2-F3  
                 `-F,S


Then, if someone has recorded an intention to work on branch S and
commits a new revision, S4 is created as a child of F3.  And someone
else who has recorded an intention to work on branch F who has the same
information commits a new revision F4 that's a child of F3.

I think fast-forward merges recorded in the repository should be
eliminated entirely unless someone explicitly forces them into
existence.  But I think there needs to be some supporting infrastructure
to make something like fast-forward merges do the right thing without
having to explicitly record a revision about them in the repo.

Just thoughts,
-- 
The best we can hope for concerning the people at large is that they
be properly armed.  -- Alexander Hamilton
-- Eric Hopper (hopper at omnifarious.org  http://www.omnifarious.org/~hopper) --
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://selenic.com/pipermail/mercurial-devel/attachments/20070610/ab2ebd10/attachment-0001.htm 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 185 bytes
Desc: This is a digitally signed message part
Url : http://selenic.com/pipermail/mercurial-devel/attachments/20070610/ab2ebd10/attachment-0001.pgp 


More information about the Mercurial-devel mailing list