[PATCH] rebase: do not add second parent to rebased changeset (drop detach option) (BC)

Augie Fackler raf at durin42.com
Thu Jun 7 08:49:04 CDT 2012


On Thu, Jun 7, 2012 at 6:58 AM,  <pierre-yves.david at logilab.fr> wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
> # Date 1339069890 -7200
> # Node ID 146a5994a0dbe3f6dd5dcb05bacfdff6f92a8c97
> # Parent  2255950e1f7663a9faa6b57040cc5c0debe7d4dd
> rebase: do not add second parent to rebased changeset (drop detach option) (BC)
>
> Rebase now always keeps the number of parents constant. merge are rebased as
> merge and non-merge are rebased with single parent. This mean that hg rebase
> always "detach" the rebase set from it's original branch if the root changeset
> only have a single parent.
>
> This only alter the behavior of rebase when using the --source option. The
> detach option itself is dropped.
>
> See in comment in code for details on the Why and How of the new behavior.
>
> All test changes have been manually validated with care.
>
> diff --git a/hgext/rebase.py b/hgext/rebase.py
> --- a/hgext/rebase.py
> +++ b/hgext/rebase.py
> @@ -46,12 +46,11 @@ testedwith = 'internal'
>     ('e', 'edit', False, _('invoke editor on commit messages')),
>     ('l', 'logfile', '',
>      _('read collapse commit message from file'), _('FILE')),
>     ('', 'keep', False, _('keep original changesets')),
>     ('', 'keepbranches', False, _('keep original branch names')),
> -    ('D', 'detach', False, _('force detaching of source from its original '
> -                            'branch')),
> +    ('D', 'detach', False, _('do nothing (DEPRECATED)')),

This makes it sound like the flag will cause rebase to be a noop. How
about only listing (DEPRECATED) in the doc for --detach?

>     ('t', 'tool', '', _('specify merge tool')),
>     ('c', 'continue', False, _('continue an interrupted rebase')),
>     ('a', 'abort', False, _('abort an interrupted rebase'))] +
>      templateopts,
>     _('hg rebase [-s REV | -b REV] [-d REV] [options]\n'
> @@ -129,11 +128,10 @@ def rebase(ui, repo, **opts):
>         collapsef = opts.get('collapse', False)
>         collapsemsg = cmdutil.logmessage(ui, opts)
>         extrafn = opts.get('extrafn') # internal, used by e.g. hgsubversion
>         keepf = opts.get('keep', False)
>         keepbranchesf = opts.get('keepbranches', False)
> -        detachf = opts.get('detach', False)
>         # keepopen is not meant for use on the command line, but by
>         # other extensions
>         keepopen = opts.get('keepopen', False)
>
>         if collapsemsg and not collapsef:
> @@ -144,12 +142,10 @@ def rebase(ui, repo, **opts):
>             if contf and abortf:
>                 raise util.Abort(_('cannot use both abort and continue'))
>             if collapsef:
>                 raise util.Abort(
>                     _('cannot use collapse with continue or abort'))
> -            if detachf:
> -                raise util.Abort(_('cannot use detach with continue or abort'))
>             if srcf or basef or destf:
>                 raise util.Abort(
>                     _('abort and continue do not allow specifying revisions'))
>             if opts.get('tool', False):
>                 ui.warn(_('tool option will be ignored\n'))
> @@ -166,16 +162,10 @@ def rebase(ui, repo, **opts):
>                 raise util.Abort(_('cannot specify both a '
>                                    'revision and a base'))
>             if revf and srcf:
>                 raise util.Abort(_('cannot specify both a '
>                                    'revision and a source'))
> -            if detachf:
> -                if not (srcf or revf):
> -                    raise util.Abort(
> -                        _('detach requires a revision to be specified'))
> -                if basef:
> -                    raise util.Abort(_('cannot specify a base with detach'))
>
>             cmdutil.bailifchanged(repo)
>
>             if not destf:
>                 # Destination defaults to the latest revision in the
> @@ -213,11 +203,11 @@ def rebase(ui, repo, **opts):
>             elif not keepf and not repo[root].mutable():
>                 raise util.Abort(_("can't rebase immutable changeset %s")
>                                  % repo[root],
>                                  hint=_('see hg help phases for details'))
>             else:
> -                result = buildstate(repo, dest, rebaseset, detachf, collapsef)
> +                result = buildstate(repo, dest, rebaseset, collapsef)
>
>             if not result:
>                 # Empty state built, nothing to rebase
>                 ui.status(_('nothing to rebase\n'))
>                 return 1
> @@ -590,26 +580,25 @@ def abort(repo, originalwd, target, stat
>             repair.strip(repo.ui, repo, repo[strippoint].node())
>         clearstatus(repo)
>         repo.ui.warn(_('rebase aborted\n'))
>         return 0
>
> -def buildstate(repo, dest, rebaseset, detach, collapse):
> +def buildstate(repo, dest, rebaseset, collapse):
>     '''Define which revisions are going to be rebased and where
>
>     repo: repo
>     dest: context
>     rebaseset: set of rev
> -    detach: boolean'''
> +    '''
>
>     # This check isn't strictly necessary, since mq detects commits over an
>     # applied patch. But it prevents messing up the working directory when
>     # a partially completed rebase is blocked by mq.
>     if 'qtip' in repo.tags() and (dest.node() in
>                             [s.node for s in repo.mq.applied]):
>         raise util.Abort(_('cannot rebase onto an applied mq patch'))
>
> -    detachset = set()
>     roots = list(repo.set('roots(%ld)', rebaseset))
>     if not roots:
>         raise util.Abort(_('no matching revisions'))
>     if len(roots) > 1:
>         raise util.Abort(_("can't rebase multiple roots"))
> @@ -621,18 +610,64 @@ def buildstate(repo, dest, rebaseset, de
>     if commonbase == dest:
>         samebranch = root.branch() == dest.branch()
>         if not collapse and samebranch and root in dest.children():
>             repo.ui.debug('source is a child of destination\n')
>             return None
> -        # rebase on ancestor, force detach
> -        detach = True
> -    if detach:
> -        detachset = repo.revs('::%d - ::%d - %d', root, commonbase, root)
>
>     repo.ui.debug('rebase onto %d starting from %d\n' % (dest, root))
>     state = dict.fromkeys(rebaseset, nullrev)
> -    state.update(dict.fromkeys(detachset, nullmerge))
> +    # Detach root from it's former parent
> +    # If root is a merge we try to preserve it.
> +    # (possible if at least one parent is ancestor of destination)
> +    #
> +    # Full Explanation
> +    # -----------------
> +    #
> +    # Rebase try to preserve the number of parents of rebased changesets:
> +    #
> +    # - A changeset with a single parent will always be rebased as a changeset
> +    #   with a single parent.
> +    #
> +    # - A merge changeset with two parent will likely be rebased as a changeset
> +    #   with two parents. (It can have fewer parents in some special cases
> +    #   ignored here)
> +    #
> +    # The goal of rebase is to make <dest> a parent of <root>. It's is
> +    # very simple if at least one parent of <root> is an ancestor of
> +    # <dest>. In this case the "rebased" version of this parent is
> +    # obviously <dest>. This is always the case when <root> where
> +    # specified using the --base option, .
> +    #
> +    # If no parent of <root> is an ancestor of <dest> this is more
> +    # complex. To keep the same number of parents for the rebased
> +    # version of <root> we need to *replace* the original parent by
> +    # <dest>. This "detach" the rebased set from it's former
> +    # localisation and rebase it onto <dest>. When "detaching" the
> +    # changeset, changes introduced by ancestors of <root> which are
> +    # not common with <dest> are "removed" from the rebased changeset.
> +    #
> +    # - If <root> has a single parent, we just need to drop it.
> +    #
> +    # - If <root> is a merge, we can't decide which parent to drop. Dropping
> +    #   both parents does not make sense.
> +    #
> +    # The table below sum up this behavior:
> +    #
> +    # +--------------------+----------------------+-------------------------+
> +    # |                    |     one parent       |  merge                  |
> +    # +--------------------+----------------------+-------------------------+
> +    # | parent in ::<dest> | new parent is <dest> | parents in ::<dest> are |
> +    # |                    |                      | remapped to <dest>      |
> +    # +--------------------+----------------------+-------------------------+
> +    # | unrelated source   | new parent is <dest> | Ambiguous rebase abort  |
> +    # +--------------------+----------------------+-------------------------+
> +    #
> +    # The actual abort is handled by `defineparents`
> +    if len(root.parents()) <= 1:
> +        # (strict) ancestors of <root> not ancestors of <dest>
> +        detachset = repo.revs('::%d - ::%d - %d', root, commonbase, root)
> +        state.update(dict.fromkeys(detachset, nullmerge))
>     return repo['.'].rev(), dest.rev(), state
>
>  def pullrebase(orig, ui, repo, *args, **opts):
>     'Call rebase after pull if the latter has been invoked with --rebase'
>     if opts.get('rebase'):
> diff --git a/tests/test-bookmarks-rebase.t b/tests/test-bookmarks-rebase.t
> --- a/tests/test-bookmarks-rebase.t
> +++ b/tests/test-bookmarks-rebase.t
> @@ -37,15 +37,14 @@ rebase
>
>   $ hg rebase -s two -d one
>   saved backup bundle to $TESTTMP/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg log
> -  changeset:   3:9163974d1cb5
> +  changeset:   3:42e5ed2cdcf4
>   bookmark:    two
>   tag:         tip
>   parent:      1:925d80f479bb
> -  parent:      2:db815d6d32e6
>   user:        test
>   date:        Thu Jan 01 00:00:00 1970 +0000
>   summary:     3
>
>   changeset:   2:db815d6d32e6
> diff --git a/tests/test-rebase-bookmarks.t b/tests/test-rebase-bookmarks.t
> --- a/tests/test-rebase-bookmarks.t
> +++ b/tests/test-rebase-bookmarks.t
> @@ -52,11 +52,11 @@ Move only rebased bookmarks
>   $ hg clone -q a a1
>
>   $ cd a1
>   $ hg up -q Z
>
> -  $ hg rebase --detach -s Y -d 3
> +  $ hg rebase -s Y -d 3
>   saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @  3: 'C' bookmarks: Y Z
>   |
> diff --git a/tests/test-rebase-cache.t b/tests/test-rebase-cache.t
> --- a/tests/test-rebase-cache.t
> +++ b/tests/test-rebase-cache.t
> @@ -102,11 +102,11 @@ Rebase part of branch2 (5-6) onto branch
>   6: 'E' branch2
>   4: 'C' branch2
>   2: 'B' branch1
>   0: 'A'
>
> -  $ hg rebase --detach -s 5 -d 8
> +  $ hg rebase -s 5 -d 8
>   saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg branches
>   branch3                        8:466cdfb14b62
>   branch2                        4:e4fdb121d036
> @@ -163,11 +163,11 @@ Rebase head of branch3 (8) onto branch2
>   | |
>   | o  1: 'branch1' branch1
>   |/
>   o  0: 'A'
>
> -  $ hg rebase --detach -s 8 -d 6
> +  $ hg rebase -s 8 -d 6
>   saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg branches
>   branch2                        8:6b4bdc1b5ac0
>   branch3                        7:653b9feb4616
> @@ -227,11 +227,11 @@ Rebase entire branch3 (7-8) onto branch2
>   | |
>   | o  1: 'branch1' branch1
>   |/
>   o  0: 'A'
>
> -  $ hg rebase --detach -s 7 -d 6
> +  $ hg rebase -s 7 -d 6
>   saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg branches
>   branch2                        7:6b4bdc1b5ac0
>   branch1                        2:0a03079c47fd (inactive)
> diff --git a/tests/test-rebase-collapse.t b/tests/test-rebase-collapse.t
> --- a/tests/test-rebase-collapse.t
> +++ b/tests/test-rebase-collapse.t
> @@ -228,11 +228,11 @@ Rebase and collapse - more than one exte
>   abort: unable to collapse, there is more than one external parent
>   [255]
>
>  Rebase and collapse - E onto H:
>
> -  $ hg rebase -s 4 --collapse
> +  $ hg rebase -s 4 --collapse # root (4) is not a merge
>   saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @    5: 'Collapsed revision
>   |\   * E
> @@ -248,11 +248,10 @@ Rebase and collapse - E onto H:
>   |/
>   o  0: 'A'
>
>   $ hg manifest
>   A
> -  B
>   C
>   D
>   E
>   F
>   H
> @@ -338,11 +337,11 @@ Create repo c:
>  Rebase and collapse - E onto I:
>
>   $ hg clone -q -u . c c1
>   $ cd c1
>
> -  $ hg rebase -s 4 --collapse
> +  $ hg rebase -s 4 --collapse # root (4) is not a merge
>   merging E
>   saved backup bundle to $TESTTMP/c1/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @    5: 'Collapsed revision
> @@ -360,11 +359,10 @@ Rebase and collapse - E onto I:
>   |/
>   o  0: 'A'
>
>   $ hg manifest
>   A
> -  B
>   C
>   D
>   E
>   G
>   I
> diff --git a/tests/test-rebase-detach.t b/tests/test-rebase-detach.t
> --- a/tests/test-rebase-detach.t
> +++ b/tests/test-rebase-detach.t
> @@ -46,11 +46,11 @@ Rebasing D onto H detaching from C:
>   | o  1: 'B'
>   |/
>   o  0: 'A'
>
>   $ hg phase --force --secret 3
> -  $ hg rebase --detach -s 3 -d 7
> +  $ hg rebase -s 3 -d 7
>   saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
>   @  7:secret 'D'
>   |
> @@ -97,11 +97,11 @@ Rebasing C onto H detaching from B:
>   | |
>   | o  1: 'B'
>   |/
>   o  0: 'A'
>
> -  $ hg rebase --detach -s 2 -d 7
> +  $ hg rebase -s 2 -d 7
>   saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @  7: 'D'
>   |
> @@ -149,11 +149,11 @@ Rebasing B onto H using detach (same as
>   | |
>   | o  1: 'B'
>   |/
>   o  0: 'A'
>
> -  $ hg rebase --detach -s 1 -d 7
> +  $ hg rebase -s 1 -d 7
>   saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @  7: 'D'
>   |
> @@ -203,11 +203,11 @@ Rebasing C onto H detaching from B and c
>   | |
>   | o  1: 'B'
>   |/
>   o  0: 'A'
>
> -  $ hg rebase --detach --collapse -s 2 -d 7
> +  $ hg rebase --collapse -s 2 -d 7
>   saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg  log -G --template "{rev}:{phase} '{desc}' {branches}\n"
>   @  6:secret 'Collapsed revision
>   |  * C
> @@ -262,11 +262,11 @@ Rebasing across null as ancestor
>   | |
>   | o  1: 'B'
>   |/
>   o  0: 'A'
>
> -  $ hg rebase --detach -s 1 -d tip
> +  $ hg rebase -s 1 -d tip
>   saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @  8: 'D'
>   |
> @@ -323,11 +323,11 @@ Verify that target is not selected as ex
>   (branch merge, don't forget to commit)
>   $ hg ci -m "Merge"
>   $ echo "J" >> F
>   $ hg ci -m "J"
>
> -  $ hg rebase -s 8 -d 7 --collapse --detach --config ui.merge=internal:other
> +  $ hg rebase -s 8 -d 7 --collapse --config ui.merge=internal:other
>   remote changed E which local deleted
>   use (c)hanged version or leave (d)eleted? c
>   saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
> @@ -368,11 +368,11 @@ Ensure --continue restores a correct sta
>   $ hg up -q 3
>   $ echo 'H2' > H
>   $ hg ci -A -m 'H2'
>   adding H
>   $ hg phase --force --secret 8
> -  $ hg rebase -s 8 -d 7 --detach --config ui.merge=internal:fail
> +  $ hg rebase -s 8 -d 7 --config ui.merge=internal:fail
>   merging H
>   warning: conflicts during merge.
>   merging H incomplete! (edit conflicts, then use 'hg resolve --mark')
>   abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
>   [255]
> diff --git a/tests/test-rebase-parameters.t b/tests/test-rebase-parameters.t
> --- a/tests/test-rebase-parameters.t
> +++ b/tests/test-rebase-parameters.t
> @@ -197,23 +197,23 @@ Specify only source (from 2 onto 8):
>   saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @  8: 'D'
>   |
> -  o    7: 'C'
> -  |\
> -  | o  6: 'I'
> +  o  7: 'C'
> +  |
> +  o  6: 'I'
> +  |
> +  o  5: 'H'
> +  |
> +  | o  4: 'G'
> +  |/|
> +  o |  3: 'F'
>   | |
> -  | o  5: 'H'
> -  | |
> -  | | o  4: 'G'
> -  | |/|
> -  | o |  3: 'F'
> -  | | |
> -  | | o  2: 'E'
> -  | |/
> -  o |  1: 'B'
> +  | o  2: 'E'
> +  |/
> +  | o  1: 'B'
>   |/
>   o  0: 'A'
>
>   $ cd ..
>
> @@ -281,11 +281,11 @@ Specify only base (from 1 onto 8):
>  Specify source and dest (from 2 onto 7):
>
>   $ hg clone -q -u . a a7
>   $ cd a7
>
> -  $ hg rebase --detach --source 2 --dest 7
> +  $ hg rebase --source 2 --dest 7
>   saved backup bundle to $TESTTMP/a7/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @  8: 'D'
>   |
> @@ -347,23 +347,23 @@ Specify only revs (from 2 onto 8)
>   saved backup bundle to $TESTTMP/a9/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
>   @  8: 'D'
>   |
> -  o    7: 'C'
> -  |\
> -  | o  6: 'I'
> +  o  7: 'C'
> +  |
> +  o  6: 'I'
> +  |
> +  o  5: 'H'
> +  |
> +  | o  4: 'G'
> +  |/|
> +  o |  3: 'F'
>   | |
> -  | o  5: 'H'
> -  | |
> -  | | o  4: 'G'
> -  | |/|
> -  | o |  3: 'F'
> -  | | |
> -  | | o  2: 'E'
> -  | |/
> -  o |  1: 'B'
> +  | o  2: 'E'
> +  |/
> +  | o  1: 'B'
>   |/
>   o  0: 'A'
>
>   $ cd ..
>
> diff --git a/tests/test-rebase-scenario-global.t b/tests/test-rebase-scenario-global.t
> --- a/tests/test-rebase-scenario-global.t
> +++ b/tests/test-rebase-scenario-global.t
> @@ -50,23 +50,23 @@ D onto H - simple rebase:
>
>   $ hg rebase -s 3 -d 7
>   saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
> -  @    7: 'D'
> -  |\
> -  | o  6: 'H'
> +  @  7: 'D'
> +  |
> +  o  6: 'H'
> +  |
> +  | o  5: 'G'
> +  |/|
> +  o |  4: 'F'
>   | |
> -  | | o  5: 'G'
> -  | |/|
> -  | o |  4: 'F'
> -  | | |
> -  | | o  3: 'E'
> -  | |/
> -  o |  2: 'C'
> +  | o  3: 'E'
> +  |/
> +  | o  2: 'C'
>   | |
> -  o |  1: 'B'
> +  | o  1: 'B'
>   |/
>   o  0: 'A'
>
>   $ cd ..
>
> @@ -78,23 +78,23 @@ D onto F - intermediate point:
>
>   $ hg rebase -s 3 -d 5
>   saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
>
>   $ hg tglog
> -  @    7: 'D'
> -  |\
> -  | | o  6: 'H'
> -  | |/
> -  | | o  5: 'G'
> -  | |/|
> -  | o |  4: 'F'
> -  | | |
> -  | | o  3: 'E'
> -  | |/
> -  o |  2: 'C'
> +  @  7: 'D'
> +  |
> +  | o  6: 'H'
> +  |/
> +  | o  5: 'G'
> +  |/|
> +  o |  4: 'F'
>   | |
> -  o |  1: 'B'
> +  | o  3: 'E'
> +  |/
> +  | o  2: 'C'
> +  | |
> +  | o  1: 'B'
>   |/
>   o  0: 'A'
>
>   $ cd ..
>
> @@ -304,11 +304,11 @@ Source phase greater or equal to destina
>   secret
>  Source phase lower than destination phase: new changeset get the phase of destination:
>   $ hg rebase -s7 -d9
>   saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c9659aac0000-backup.hg (glob)
>   $ hg log --template "{phase}\n" -r 9
> -  secret
> +  draft
>
>   $ cd ..
>
>  Test for revset
>
> @@ -402,24 +402,24 @@ Base on have one descendant heads we ask
>   |
>   o  11: 'H'
>   |
>   o  10: 'G'
>   |
> -  o    9: 'D'
> -  |\
> -  | | o  8: 'I'
> +  o  9: 'D'
> +  |
> +  | o  8: 'I'
> +  | |
> +  | o  7: 'H'
> +  | |
> +  | o  6: 'G'
> +  | |
> +  | | o  5: 'F'
>   | | |
> -  | | o  7: 'H'
> -  | | |
> -  | | o  6: 'G'
> -  | | |
> -  | | | o  5: 'F'
> -  | | | |
> -  | | | o  4: 'E'
> -  | | |/
> -  | | o  3: 'D'
> +  | | o  4: 'E'
>   | |/
> +  | o  3: 'D'
> +  | |
>   | o  2: 'C'
>   | |
>   o |  1: 'B'
>   |/
>   o  0: 'A'
> @@ -439,24 +439,24 @@ rebase subset
>   $ hg tglog
>   @  11: 'H'
>   |
>   o  10: 'G'
>   |
> -  o    9: 'D'
> -  |\
> -  | | o  8: 'I'
> +  o  9: 'D'
> +  |
> +  | o  8: 'I'
> +  | |
> +  | o  7: 'H'
> +  | |
> +  | o  6: 'G'
> +  | |
> +  | | o  5: 'F'
>   | | |
> -  | | o  7: 'H'
> -  | | |
> -  | | o  6: 'G'
> -  | | |
> -  | | | o  5: 'F'
> -  | | | |
> -  | | | o  4: 'E'
> -  | | |/
> -  | | o  3: 'D'
> +  | | o  4: 'E'
>   | |/
> +  | o  3: 'D'
> +  | |
>   | o  2: 'C'
>   | |
>   o |  1: 'B'
>   |/
>   o  0: 'A'
> @@ -480,24 +480,24 @@ rebase subset with multiple head
>   |
>   | o  11: 'F'
>   | |
>   | o  10: 'E'
>   |/
> -  o    9: 'D'
> -  |\
> -  | | o  8: 'I'
> +  o  9: 'D'
> +  |
> +  | o  8: 'I'
> +  | |
> +  | o  7: 'H'
> +  | |
> +  | o  6: 'G'
> +  | |
> +  | | o  5: 'F'
>   | | |
> -  | | o  7: 'H'
> -  | | |
> -  | | o  6: 'G'
> -  | | |
> -  | | | o  5: 'F'
> -  | | | |
> -  | | | o  4: 'E'
> -  | | |/
> -  | | o  3: 'D'
> +  | | o  4: 'E'
>   | |/
> +  | o  3: 'D'
> +  | |
>   | o  2: 'C'
>   | |
>   o |  1: 'B'
>   |/
>   o  0: 'A'
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list