[prev in list] [next in list] [prev in thread] [next in thread]
List: mercurial
Subject: Defining and manipulating a WIP feature branch
From: Andrew Halberstadt <ahalberstadt () mozilla ! com>
Date: 2015-02-27 21:46:39
Message-ID: 54F0E5BF.1020304 () mozilla ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
Hi,
I recently switched from mq to a multi-headed development workflow. The
new workflow is much better, but there were still some things missing,
namely the concept of a "feature branch" (like a git-style branch).
Bookmarks come close, but it is difficult to guess what they are based
on, there is no concept of "ownership" from a commit to a bookmark. The
revset "only(<bookmark>) and not public()" comes pretty close, but
doesn't quite get there. I want to be able to rebase bookmarks on top of
one another, and have a convenient shortcut for expanding a bookmark
label to the full revset of commits within that bookmark.
E.g, with:
o rev: 5
> bookmark: C
>
o rev: 4
>
o rev: 3
> bookmark: B
>
o rev: 2
>
o rev: 1
> bookmark: A
>
o rev: 0
I want "hg log -r B" to return 2:3. I came up with an informal
definition for a WIP feature. A commit /C/ is "within" a WIP feature
branch ending at revision /R/ if:
1. /C /is/R/ or /C/ is an ancestor of /R/
2. /C/ is not public
3. /C/ is not a merge commit
4. no bookmarks exist in [/C/, /R/) for /C/ != /R/
There's no requirement that /R/ be a head, nor any requirement that /R/
have a bookmark. This definition can be implemented by a somewhat
complicated revset (thanks to smacleod for coming up with it):
[revsetalias]
feature($1) = ($1 or (ancestors($1) and not (excludemarks($1) or hg \
ancestors(excludemarks($1))))) and not public() and not merge() excludemarks($1) = \
ancestors(parents($1)) and bookmark()
This lets you manipulate a feature* as a series of commits:
hg log -r 'feature(B)'
That revset is a bit tricky to grok, and it requires some extra typing,
so I wrote an extension:
https://bitbucket.org/halbersa/bookbinder
Bookbinder does two things:
1. It defines an actual 'feature' revset (not an alias)
2. It wraps (almost) all commands with a --rev argument. If --rev
<bookmark> is detected, <bookmark> is replaced with
'feature(<bookmark>)'. It is still possible to treat the bookmark as
a label by escaping it with a period.
Bookbinder makes it really convenient to do things like:
hg log -r <bookmark>
hg fold -r <bookmark>
hg rebase -r <bookmark> -d <dest>
hg graft -r <bookmark>
etc..
I'd like to get feedback on this approach. Is the definition sane? Is
the extension sane? Would others find it useful? What things could be
done in mercurial core to make the situation better? I'm pretty new to
the world of mercurial extensions/development, so please bear with me as
I figure out what is or isn't a good approach.
Cheers,
Andrew
* I'm not too happy with the name feature, but couldn't think of
anything better.. suggestions welcome!
[Attachment #5 (text/html)]
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<p>Hi,<br>
</p>
<p>I recently switched from mq to a multi-headed development
workflow. The new workflow is much better, but there were still
some things missing, namely the concept of a "feature branch"
(like a git-style branch). Bookmarks come close, but it is
difficult to guess what they are based on, there is no concept of
"ownership" from a commit to a bookmark. The revset
"only(<bookmark>) and not public()" comes pretty close, but
doesn't quite get there. I want to be able to rebase bookmarks on
top of one another, and have a convenient shortcut for expanding a
bookmark label to the full revset of commits within that bookmark.</p>
E.g, with:<br>
<br>
o rev: 5
<br>
| bookmark: C
<br>
|
<br>
o rev: 4
<br>
|
<br>
o rev: 3
<br>
| bookmark: B
<br>
|
<br>
o rev: 2
<br>
|
<br>
o rev: 1
<br>
| bookmark: A
<br>
|
<br>
o rev: 0
<br>
<br>
I want "hg log -r B" to return 2:3. I came up with an informal
definition for a WIP feature. A commit <i>C</i> is "within" a WIP
feature branch ending at revision <i>R</i> if:<br>
<ol>
<li><i>C </i>is<i> R</i> or <i>C</i> is an ancestor of <i>R</i></li>
<li><i>C</i> is not public</li>
<li><i>C</i> is not a merge commit</li>
<li>no bookmarks exist in [<i>C</i>, <i>R</i>) for <i>C</i> != <i>R</i><br>
</li>
</ol>
There's no requirement that <i>R</i> be a head, nor any requirement
that <i>R</i> have a bookmark. This definition can be implemented
by a somewhat complicated revset (thanks to smacleod for coming up
with it):<br>
<pre wrap=""> [revsetalias]
feature($1) = ($1 or (ancestors($1) and not (excludemarks($1) or hg \
ancestors(excludemarks($1))))) and not public() and not merge() excludemarks($1) = \
ancestors(parents($1)) and bookmark()</pre> This lets you manipulate a feature* as a \
series of commits:<br> hg log -r 'feature(B)'<br>
<br>
That revset is a bit tricky to grok, and it requires some extra
typing, so I wrote an extension:<br>
<a class="moz-txt-link-freetext" \
href="https://bitbucket.org/halbersa/bookbinder">https://bitbucket.org/halbersa/bookbinder</a><br>
<br>
Bookbinder does two things:<br>
<ol>
<li>It defines an actual 'feature' revset (not an alias)<br>
</li>
<li>It wraps (almost) all commands with a --rev argument. If --rev
<bookmark> is detected, <bookmark> is replaced with
'feature(<bookmark>)'. It is still possible to treat the
bookmark as a label by escaping it with a period.<br>
</li>
</ol>
Bookbinder makes it really convenient to do things like:<br>
hg log -r <bookmark><br>
hg fold -r <bookmark><br>
hg rebase -r <bookmark> -d <dest><br>
hg graft -r <bookmark><br>
etc..<br>
<br>
I'd like to get feedback on this approach. Is the definition sane?
Is the extension sane? Would others find it useful? What things
could be done in mercurial core to make the situation better? I'm
pretty new to the world of mercurial extensions/development, so
please bear with me as I figure out what is or isn't a good
approach.<br>
<br>
Cheers,<br>
Andrew<br>
<br>
* I'm not too happy with the name feature, but couldn't think of
anything better.. suggestions welcome!<br>
</body>
</html>
[Attachment #6 (text/plain)]
_______________________________________________
Mercurial mailing list
Mercurial@selenic.com
http://selenic.com/mailman/listinfo/mercurial
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic