[PATCH 3 of 5] Add option to heads to show only heads for current branch

Alexis S. L. Carvalho alexis at cecm.usp.br
Tue Jun 5 13:40:52 CDT 2007


Thus spake Eric Hopper:
> # HG changeset patch
> # User Eric Hopper <hopper at omnifarious.org>
> # Date 1181054192 25200
> # Node ID f32f2c89f227b4ce07c60882c9091f078b18a1ed
> # Parent  8b12d7cf038ff6569af620d20cb0d04cc66063bd
> Add option to heads to show only heads for current branch.
> 
> diff --git a/mercurial/commands.py b/mercurial/commands.py
> --- a/mercurial/commands.py
> +++ b/mercurial/commands.py
> @@ -1253,10 +1253,13 @@ def heads(ui, repo, **opts):
>      changesets. They are where development generally takes place and
>      are the usual targets for update and merge operations.
>      """
> +    branch = None
> +    if opts['branch']:
> +        branch = repo.dirstate.branch()
>      if opts['rev']:
> -        heads = repo.heads(repo.lookup(opts['rev']))
> +        heads = repo.heads(repo.lookup(opts['rev']), branch=branch)
>      else:
> -        heads = repo.heads()
> +        heads = repo.heads(branch=branch)
>      displayer = cmdutil.show_changeset(ui, repo, opts)
>      for n in heads:
>          displayer.show(changenode=n)
> @@ -2822,6 +2825,7 @@ table = {
>      "heads":
>          (heads,
>           [('', 'style', '', _('display using template map file')),
> +          ('b', 'branch', None, _("show even inactive heads for just the current branch")),

The heads command in 0.9.3 (which is still the most recent version)
still has a -b/--branches option for old-style branches...

This interface also requires a "hg branch foo; hg heads -b" to see the
heads of a non-current branch, which is not exactly optimal, and which
just won't work if you can't write .hg/branch.

Maybe "hg [-b] [branch]" (-b is still a boolean option) - if you specify
branch, print heads of that branch; if you specify -b, print heads of
the current branch; if you specify both, err...

>            ('r', 'rev', '', _('show only heads which are descendants of rev')),
>            ('', 'template', '', _('display with template'))],
>           _('hg heads [-r REV]')),
> diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
> --- a/mercurial/localrepo.py
> +++ b/mercurial/localrepo.py
> @@ -1079,12 +1079,40 @@ class localrepository(repo.repository):
>                  self.dirstate.update([dest], "a")
>              self.dirstate.copy(source, dest)
>  
> -    def heads(self, start=None):
> +    def heads(self, start=None, branch=None):
> +        if branch is not None:
> +            return self.bheads(branch, start)
>          heads = self.changelog.heads(start)
>          # sort the output in rev descending order
>          heads = [(-self.changelog.rev(h), h) for h in heads]
>          heads.sort()
>          return [n for (r, n) in heads]
> +
> +    def bheads(self, branch, start=None):
> +        branches = self.branchtags()
> +        if branch not in branches:
> +            ui.warn(_("%s is a new branch that has no heads yet.\n") % (branch,))

This warning should be in commands.py

> +            return []
> +        heads = [branches[branch]]
> +        p = self.changelog.parents(heads[0])
> +        parents = dict.fromkeys([n for n in p if n != nullid], 0)
> +        for rev in xrange(self.changelog.rev(heads[0]) - 1, -1, -1):
> +            node = self.changelog.node(rev)
> +            if node in parents:
> +                p = self.changelog.parents(node)
> +                parents.update(dict.fromkeys([n for n in p if n != nullid], 0))
> +                del parents[node]
> +            elif self.changectx(rev).branch() == branch:
> +                heads.append(node)
> +                p = self.changelog.parents(node)
> +                parents.update(dict.fromkeys([n for n in p if n != nullid], 0))

Some comments outlining the algorithm (or at least the basic idea) would
be nice.

I'd say that using rev/parentrevs/nullrev would be a bit faster, but
since you're reading a good chunk of the changelog, that probably won't
be noticeable.  The dict.fromkeys([...]) in the loop also look somewhat
heavy-handed.

We should probably just save all the heads in the branch cache.

> +        if start is not None:
> +            heads = self.changelog.nodesbetween([start], heads)[2]
> +            if len(heads) < 0:
> +                self.ui.warn(_("No  changes on branch %s are reachable from "\
> +                                   "revision %d\n") % \
> +                                 (branch, self.changelog.rev(start)))

This warning should also go in commands.py (without the extra space
after "No").  You probably want to test for "not heads", since
len(heads) is probably never negative :)

Extra brownie points if you make the exit code non-zero when you print
the warnings.

Maybe the warnings should be printed only with --verbose?  Or maybe
--quiet should suppress them...

> +        return heads
>  
>      def branches(self, nodes):
>          if not nodes:
> 

Alexis


More information about the Mercurial-devel mailing list