Lightweight branches (Re: Why we didn't migrate to Mercurial (long))

Kastner Masilko, Friedrich kastner-masilko at at.festo.com
Tue Oct 9 07:48:48 UTC 2012


> From: Arne Babenhauserheide [mailto:arne_bab at web.de]
> 
> At Mon, 8 Oct 2012 09:27:30 +0000,
> > Except that I talked about "hg update default", not "hg update".
> 
> Then it's easy: Just set the bookmark `default`. It wins against the
> default branch.

Now you are starting to confuse me :) . My question "why do you want to update to default at all" was in reply to Stephen's statement here:
> I guess the only thing that still confuses me is that with bookmarks, 
> you cannot really have your "default branch" and your "bookmarked 
> branches" because the bookmarks are all on the default branch too so
> "hg update default" doesn't do what you might think. And there is no
> "hg update -r 'branch(default) and not bookmarked()'"
> (Yes, that too might make no sense as there could be numerous 
> anonymous heads to default, but I'm assuming that there aren't.) So 
> once you create one bookmark, you really have to create a bookmark
> for default too or you have no simple way to identify it.

There he noted that once you have bookmarks alongside named-branches, "hg update default" can confuse you. But if you use a bookmark workflow - and no named-branch or mixed one - then why do you want to "hg update default" at all? If you know what bookmark you want, then go there. If you don't know what bookmark you want, reconsider the bookmark workflow.

Named branches are node coloring, in contrast to bookmarks being pointers. It is no wonder that mixing those concepts is confusing.
 
> > If you want to use a bookmark workflow, you have to use "hg update
> <bookmark>", because the named-branch "default" has no meaning anymore.
> >
> > What would you expect in a workflow with bookmarks in a situation
> like so:
> >
> > -*---o <- bookmark master
> >  \-o <- bookmark myBranch
> 
> I don't yet have expectations for these cases. But I know what I would
> like to see:
> 
> - One non-bookmarked head: use that.
> - ... more below.

If you have one non-bookmarked head, you already have a mixed-mode situation. If we take Git as an example - with Git's branching model being the reason why we have bookmarks here IMHO - this situation would not exist. There are no anonymous heads with Git. Well, technically there are, but they wouldn't be used as default update targets, anyway.

In light of this, it would surprise me to have 2 orthogonal concepts suddenly influencing each other on "hg update". 

> > If you mix both concepts - either willingly or because you simply
> don't know it better - you'll get confused sometimes.
> 
> That is a problem, I think, because named branches and bookmarks can
> happily coexist - and there are reasons for using both.
> 
> Example: Named branches for development lines, bookmarks for short-term
> separation. Python uses named branches for Python versions which get
> developed side-by-side (2.7, 3.2 and 3.3).

I agree. There are good reasons to use a mixed-mode workflow. But then you should be aware that you use it.

> Now it might be useful to specify:
> 
> - Never implicitely cross the named branch boundary.
> - If a given bookmark is active, stay on that. Only change the checked-
> out revision if the other side updated the bookmark.
> - If no bookmark is active and there is only one non-bookmarked head,
> use that.
> - If no bookmark is active and there are multiple non-bookmarked heads,
> ask for a head.
> - If there are no non-bookmarked heads, but only one head has my
> revision as ancestor, use that head.
> - If there are no non-bookmarked heads, and multiple heads have my
> revision as ancestor, ask for a head.

Wow. That sounds like much magic is going into "hg update" to resolve the head it should go to. I'm pretty sure it would more often than not surprise me where I end up. And if that happens too often, I simply take the easy way out and always update exactly to where I want it. Which would bring me back to "hg update <whereIwantToBe>".

As a side-note: wouldn't 2 (active bookmark, stay on that) mean a Git-like remote branch tracking mechanism, where your current bookmark "master" tracks a remote "master at default" bookmark, so you can "stay" on it with "hg update"? Otherwise I don't understand it, because if you are on a bookmark, there is no way to determine what head of your descendant lines is associated with your current pointer.

Now don't get me wrong, but the simple mechanisms in HG's basic operations is what I love. They nicely fit into my head. The list you proposed up there is already 3 rules too long for that IMHO.

> Organisatorically that means:
> 
> - Named branches are subprojects. You never switch between them without
> explicit user-request.
> - Bookmarks are branches of development. You switch to them, when they
> get merged with your branch.
> - Multiple anonymous heads are a purely local tool. No need to switch
> implicitely: Creating two anonymous heads on the same branch or
> bookmark in a public repository is an error condition.

I think 1 and 3 is already in effect, isn't it? You can't switch named-branches with "hg update" alone, because it will always put you on the tip-most (non-topological) head of the branch you are on. Or do you mean an even "harder" barrier than "hg update <branch-name>"? Also, do you mean that the standard "creates remote head" abort is not enough?
As for 2, I think I don't understand that. Let's again take Git for an example: there you switch to a branch by means of "git checkout <branch>". With "git merge <branch>" you could "fast-forward" your current branch pointer to the target branch, if topology allows for that. Do you mean this behaviour when you say "switch to them when they get merged in"?


For me it looks like the main problem is to always know - as you already noted - where the "main line" is for a given session of development, so that "hg update" does TheRightThing(TM). My proposal would be to implement an extension WhereThePartyIsAt that offers a command "hg partyat <revset>" (yes, the names are a joke, they are just examples). This command stores the revset in a file in .hg for the given working copy and installs a hook that with every parameter-free "hg update" evaluates the revset and updates to the resolved commit (or the tip-most of a set). A "hg partyat master" will then prepare your session for development against master. A "hg partyat 'branch(p1()) and descendants(p1()) and head() and not bookmark()'" will then make "hg update" to update to the current branch's tip-most non-bookmarked head, if it is a descendant. If not, it will abort with empty revset error.

But in the end this would only be a convenience extension to use "hg update", instead of putting the above mentioned revsets into an alias like "newest = <revset>", and then always issuing "hg update newest".

regards,
Fritz



Development Software Systems
Festo Gesellschaft m.b.H.
Linzer Strasse 227
Austria - 1140 Wien

Firmenbuch Wien
FN 38435y
UID: ATU14650108

Tel: +43(1)91075-198
Fax: +43(1)91075-282
www.festo.at

Der Inhalt dieses E-Mails ist ausschliesslich fuer den bezeichneten Adressaten bestimmt. Jede Form der Kenntnisnahme,
Veroeffentlichung, Vervielfaeltigung oder Weitergabe des Inhalts dieses E-Mails durch unberechtigte Dritte ist unzulaessig. Wir
bitten Sie, sich mit dem Absender des E-Mails in Verbindung zu setzen, falls Sie nicht der Adressat dieses E-Mails sind und das
Material von Ihrem Computer zu loeschen. 

This e-mail and any attachments are confidential and intended solely for the addressee. The perusal, publication, copying or
dissemination of the contents of this e-mail by unauthorised third parties is prohibited. If you are not the intended recipient of this
e-mail, please delete it and immediately notify the sender.




More information about the Mercurial mailing list