[PATCH 6 of 6 RFC] destutil: choose non-closed branch head as default update destination (BC)

Pierre-Yves David pierre-yves.david at ens-lyon.org
Wed Feb 24 18:19:50 EST 2016



On 02/24/2016 03:17 PM, FUJIWARA Katsunori wrote:
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
> # Date 1456322433 -32400
> #      Wed Feb 24 23:00:33 2016 +0900
> # Node ID ae5d291a6dcb96683eae3c4e33575297fa113fbb
> # Parent  1f9b3d38e380b018cbe10ed1acee882c014e3763
> destutil: choose non-closed branch head as default update destination (BC)
>
> Before this patch, destupdate() returns the tipmost (descendant)
> branch head regardless of closed or not. But updating to closed branch
> head isn't reasonable for ordinary workflow, because:
>
>    - "hg heads" doesn't show closed heads (= updated parent itself) by
>      default
>
>    - subsequent committing on it re-opens closed branch
>
>      even if inactivation of closed head is needed, update destination
>      isn't it, because it should be merged into to another branch in
>      such case.

Excluding closed head from update makes a lot of sense to me. But we 
probably need some better messaging around the no-op update. I'm not 
exactly sure no-op update is the right choice if there is nothing but 
closed head above. However giving priority to non-closed head seems an 
obvious way to go here.

I need to think about the "no non-closed heads in .::" case a bit more.

Thanks for looking into that.

>
> This patch chooses non-closed branch head as default update
> destination.
>
> This patch changes not only normal lookup code path, but also "no
> default branch" code path, for consistency.
>
> If no appropriate default update destination is found, destupdate()
> returns '.' as destination to work as no-op at updating. 'None' isn't
> reasonable for this purpose, because:
>
>    - repo[node] returns useless rev/node if node=None
>    - merge.update() re-invokes destupdate() for None destination
>
> diff --git a/mercurial/destutil.py b/mercurial/destutil.py
> --- a/mercurial/destutil.py
> +++ b/mercurial/destutil.py
> @@ -93,14 +93,15 @@ def _destupdatebranch(repo, clean, check
>       movemark = node = None
>       currentbranch = wc.branch()
>       if currentbranch in repo.branchmap():
> -        heads = repo.branchheads(currentbranch, closed=True)
> +        heads = repo.branchheads(currentbranch)
>           if heads:
>               node = repo.revs('max(.::(%ln))', heads).first()
>           if bookmarks.isactivewdirparent(repo):
>               movemark = repo['.'].node()
>       else:
>           if currentbranch == 'default': # no default branch!
> -            node = repo.lookup('tip') # update to tip
> +            # update to the tipmost non-closed branch head
> +            node = repo.revs('max(head() and not closed())').first()
>           else:
>               raise error.Abort(_("branch %s not found") % currentbranch)
>       return node, movemark, None
> @@ -130,6 +131,11 @@ def destupdate(repo, clean=False, check=
>           node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
>           if node is not None:
>               break
> +    else:
> +        # udate to current parent (= no-op), because no appropriate
> +        # default destination is found
> +        node = '.'
> +
>       rev = repo[node].rev()
>
>       _destupdatevalidate(repo, rev, clean, check)
> @@ -366,6 +372,16 @@ def _statusotherbranchheads(ui, repo):
>           if otherheads:
>               ui.status(_('%i other heads for branch "%s"\n') %
>                         (len(otherheads), currentbranch))
> +    elif len(repo): # omit redundant message in empty repository
> +        if not heads:
> +            if currentbranch not in repo.branchmap():
> +                # this is "update to the tipmost non-closed branch head" case
> +                ui.status(_('all branches are closed\n'))
> +            else:
> +                ui.status(_('all heads of branch "%s" are closed\n') %
> +                          currentbranch)
> +        elif not len(repo.revs('parents()::(%ln)', heads)):
> +            ui.status(_('all descendant branch heads are closed\n'))
>
>   def statusotherdests(ui, repo):
>       """Print message about other head"""
> diff --git a/tests/test-update-branches.t b/tests/test-update-branches.t
> --- a/tests/test-update-branches.t
> +++ b/tests/test-update-branches.t
> @@ -196,6 +196,24 @@ if on the closed branch head:
>     1 other heads for branch "default"
>     parent=6
>
> +if only one descendant non-closed branch head exists:
> +- update to it, even if its revision is less than closed one
> +- "N other heads for ...." message isn't displayed
> +
> +  $ norevtest "non-closed 2 should be chosen" clean 1
> +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  parent=2
> +
> +if all descendant branch heads are closed:
> +- updating is no-op
> +- "N other heads for ...." message isn't displayed
> +- "all descendant branch ...." is displayed
> +
> +  $ norevtest "all descendant branch heads are closed" clean 3
> +  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  all descendant branch heads are closed
> +  parent=3
> +
>   Test updating if all branch heads are closed
>
>   if on the closed branch head:
> @@ -208,6 +226,55 @@ if on the closed branch head:
>     0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>     parent=6
>
> +if not on the closed branch head:
> +- updating is no-op
> +- "all heads of branch ...." message is displayed
> +
> +  $ norevtest "all heads of branch default are closed" clean 1
> +  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  all heads of branch "default" are closed
> +  parent=1
> +
> +  $ cd ..
> +
> +Test updating if "default" branch doesn't exist and no revision is
> +checked out (= "default" is used as current branch)
> +
> +  $ hg init no-default-branch
> +  $ cd no-default-branch
> +
> +  $ hg branch foobar
> +  marked working directory as branch foobar
> +  (branches are permanent and global, did you want a bookmark?)
> +  $ echo a > a
> +  $ hg commit -m "#0" -A
> +  adding a
> +  $ echo 1 >> a
> +  $ hg commit -m "#1"
> +  $ hg update -q 0
> +  $ echo 3 >> a
> +  $ hg commit -m "#2"
> +  created new head
> +  $ hg commit --close-branch -m "#3"
> +
> +if there is at least one non-closed branch head:
> +- update to the tipmost branch head
> +
> +  $ norevtest "non-closed 1 should be chosen" clean null
> +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  parent=1
> +
> +if all branch heads are closed
> +- updating is no-op
> +- "all branches are closed" message is displayed
> +
> +  $ hg update -q -C 1
> +  $ hg commit --close-branch -m "#4"
> +
> +  $ norevtest "all branches are closed" clean null
> +  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  all branches are closed
> +
>     $ cd ../b1
>
>   Test obsolescence behavior
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>

-- 
Pierre-Yves David


More information about the Mercurial-devel mailing list