# HG changeset patch # User Eric Hopper # Date 1182267463 25200 # Node ID 8e503fa54d2d49ba265b3c5924b18d8df6c3768c # Parent 7c80e3e6f03066499adfef9992cb824fb59a02b4 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 @@ -1206,19 +1206,51 @@ def grep(ui, repo, pattern, *pats, **opt found = display(fn, rev, {}, state) or found return (not found and 1) or 0 -def heads(ui, repo, **opts): - """show current repository heads - - Show all repository head changesets. - - Repository "heads" are changesets that don't have children +def heads(ui, repo, *branchrevs, **opts): + """show current repository heads or show branch heads + + With no arguments, show all repository head changesets. + + If branch or revisions names are given this will show the heads of + the specified branches or the branches those revisions are tagged + with. + + Repository "heads" are changesets that don't have child changesets. They are where development generally takes place and are the usual targets for update and merge operations. + + Branch heads are changesets that have a given branch tag, but have + no child changesets with that tag. They are usually where + development on the given branch takes place. """ if opts['rev']: - heads = repo.heads(repo.lookup(opts['rev'])) + start = repo.lookup(opts['rev']) + else: + start = None + if not branchrevs: + # Assume we're looking repo-wide heads if no revs were specified. + heads = repo.heads(start) else: - heads = repo.heads() + heads = [] + visitedset = set() + displayer = cmdutil.show_changeset(ui, repo, opts) + for branchrev in branchrevs: + branch = repo.changectx(branchrev).branch() + if branch in visitedset: + continue + visitedset.add(branch) + bheads = repo.branchheads(branch, start) + if not bheads: + if branch != branchrev: + ui.warn(_("no changes on branch %s containing %s are " + "reachable from %s\n") + % (branch, branchrev, opts['rev'])) + else: + ui.warn(_("no changes on branch %s are reachable from %s\n") + % (branch, opts['rev'])) + heads.extend(bheads) + if not heads: + return 1 displayer = cmdutil.show_changeset(ui, repo, opts) for n in heads: displayer.show(changenode=n) @@ -2790,7 +2822,7 @@ table = { [('', 'style', '', _('display using template map file')), ('r', 'rev', '', _('show only heads which are descendants of rev')), ('', 'template', '', _('display with template'))], - _('hg heads [-r REV]')), + _('hg heads [-r REV] [REV]...')), "help": (help_, [], _('hg help [COMMAND]')), "identify|id": (identify, [], _('hg identify')), "import|patch": diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1019,6 +1019,52 @@ class localrepository(repo.repository): heads.sort() return [n for (r, n) in heads] + def branchheads(self, branch, start=None): + branches = self.branchtags() + if branch not in branches: + return [] + # The basic algorithm is this: + # + # Start from the branch tip since there are no later revisions that can + # possibly be in this branch, and the tip is a guaranteed head. + # + # Remember the tip's parents as the first ancestors, since these by + # definition are not heads. + # + # Step backwards from the brach tip through all the revisions. We are + # guaranteed by the rules of Mercurial that we will now be visiting the + # nodes in reverse topological order (children before parents). + # + # If a revision is one of the ancestors of a head then we can toss it + # out of the ancestors set (we've already found it and won't be + # visiting it again) and put its parents in the ancestors set. + # + # Otherwise, if a revision is in the branch it's another head, since it + # wasn't in the ancestor list of an existing head. So add it to the + # head list, and add its parents to the ancestor list. + # + # If it is not in the branch ignore it. + # + # Once we have a list of heads, use nodesbetween to filter out all the + # heads that cannot be reached from startrev. There may be a more + # efficient way to do this as part of the previous algorithm. + + set = util.set + heads = [self.changelog.rev(branches[branch])] + # Don't care if ancestors contains nullrev or not. + ancestors = set(self.changelog.parentrevs(heads[0])) + for rev in xrange(heads[0] - 1, nullrev, -1): + if rev in ancestors: + ancestors.update(self.changelog.parentrevs(rev)) + ancestors.remove(rev) + elif self.changectx(rev).branch() == branch: + heads.append(rev) + ancestors.update(self.changelog.parentrevs(rev)) + heads = [self.changelog.node(rev) for rev in heads] + if start is not None: + heads = self.changelog.nodesbetween([start], heads)[2] + return heads + def branches(self, nodes): if not nodes: nodes = [self.changelog.tip()] diff --git a/tests/test-bheads b/tests/test-bheads new file mode 100755 --- /dev/null +++ b/tests/test-bheads @@ -0,0 +1,108 @@ +#!/bin/sh + +hg init a +cd a +echo 'root' >root +hg add root +hg commit -d '0 0' -u test -m "Adding root node" +hg heads +echo '-------' +hg heads . + +echo '=======' +echo 'a' >a +hg add a +hg branch a +hg commit -d '1 0' -u test -m "Adding a branch" +hg heads +echo '-------' +hg heads . + +echo '=======' +hg update -C 0 +echo 'b' >b +hg add b +hg branch b +hg commit -d '2 0' -u test -m "Adding b branch" +hg heads +echo '-------' +hg heads . + +echo '=======' +echo 'bh1' >bh1 +hg add bh1 +hg commit -d '3 0' -u test -m "Adding b branch head 1" +hg heads +echo '-------' +hg heads . + +echo '=======' +hg update -C 2 +echo 'bh2' >bh2 +hg add bh2 +hg commit -d '4 0' -u test -m "Adding b branch head 2" +hg heads +echo '-------' +hg heads . + +echo '=======' +hg update -C 2 +echo 'bh3' >bh3 +hg add bh3 +hg commit -d '5 0' -u test -m "Adding b branch head 3" +hg heads +echo '-------' +hg heads . + +echo '=======' +hg merge 4 +hg commit -d '6 0' -u test -m "Merging b branch head 2 and b branch head 3" +hg heads +echo '-------' +hg heads . + +echo '=======' +echo 'c' >c +hg add c +hg branch c +hg commit -d '7 0' -u test -m "Adding c branch" +hg heads +echo '-------' +hg heads . + +echo '=======' +hg heads -r 3 . +echo $? +echo '-------' +hg heads -r 2 . +echo $? +echo '-------' +hg update -C 4 +echo $? +echo '-------' +hg heads -r 3 . +echo $? +echo '-------' +hg heads -r 2 . +echo $? +echo '-------' +hg heads -r 7 . +echo $? + +echo '=======' +for i in 0 1 2 3 4 5 6 7; do + hg update -C "$i" + hg heads + echo '-------' + hg heads . + echo '-------' +done + +echo '=======' +for i in a b c z; do + hg heads "$i" + echo '-------' +done + +echo '=======' +hg heads 0 1 2 3 4 5 6 7 diff --git a/tests/test-bheads.out b/tests/test-bheads.out new file mode 100644 --- /dev/null +++ b/tests/test-bheads.out @@ -0,0 +1,608 @@ +changeset: 0:19709c5a4e75 +tag: tip +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: Adding root node + +------- +changeset: 0:19709c5a4e75 +tag: tip +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: Adding root node + +======= +marked working directory as branch a +changeset: 1:dd6b440dd85a +branch: a +tag: tip +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 1:dd6b440dd85a +branch: a +tag: tip +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +======= +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +marked working directory as branch b +changeset: 2:ac22033332d1 +branch: b +tag: tip +parent: 0:19709c5a4e75 +user: test +date: Thu Jan 01 00:00:02 1970 +0000 +summary: Adding b branch + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 2:ac22033332d1 +branch: b +tag: tip +parent: 0:19709c5a4e75 +user: test +date: Thu Jan 01 00:00:02 1970 +0000 +summary: Adding b branch + +======= +changeset: 3:aee39cd168d0 +branch: b +tag: tip +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 3:aee39cd168d0 +branch: b +tag: tip +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +======= +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +changeset: 4:22df7444f7c1 +branch: b +tag: tip +parent: 2:ac22033332d1 +user: test +date: Thu Jan 01 00:00:04 1970 +0000 +summary: Adding b branch head 2 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 4:22df7444f7c1 +branch: b +tag: tip +parent: 2:ac22033332d1 +user: test +date: Thu Jan 01 00:00:04 1970 +0000 +summary: Adding b branch head 2 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +======= +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +changeset: 5:0d57af4f9583 +branch: b +tag: tip +parent: 2:ac22033332d1 +user: test +date: Thu Jan 01 00:00:05 1970 +0000 +summary: Adding b branch head 3 + +changeset: 4:22df7444f7c1 +branch: b +parent: 2:ac22033332d1 +user: test +date: Thu Jan 01 00:00:04 1970 +0000 +summary: Adding b branch head 2 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 5:0d57af4f9583 +branch: b +tag: tip +parent: 2:ac22033332d1 +user: test +date: Thu Jan 01 00:00:05 1970 +0000 +summary: Adding b branch head 3 + +changeset: 4:22df7444f7c1 +branch: b +parent: 2:ac22033332d1 +user: test +date: Thu Jan 01 00:00:04 1970 +0000 +summary: Adding b branch head 2 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +======= +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +changeset: 6:00432327d822 +branch: b +tag: tip +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 6:00432327d822 +branch: b +tag: tip +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +======= +marked working directory as branch c +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +======= +No changes on branch c (the branch of revision .) are reachable from revision 3 +1 +------- +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +0 +------- +0 files updated, 0 files merged, 2 files removed, 0 files unresolved +0 +------- +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +0 +------- +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +0 +------- +No changes on branch b (the branch of revision .) are reachable from revision 7 +1 +======= +0 files updated, 0 files merged, 2 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 0:19709c5a4e75 +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: Adding root node + +------- +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +------- +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +------- +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +------- +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +------- +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +------- +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +------- +======= +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +------- +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +------- +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch + +------- +abort: unknown revision 'z'! +------- +======= +changeset: 0:19709c5a4e75 +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: Adding root node + +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +changeset: 6:00432327d822 +branch: b +parent: 5:0d57af4f9583 +parent: 4:22df7444f7c1 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: Merging b branch head 2 and b branch head 3 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 7:9fb091bb9835 +branch: c +tag: tip +user: test +date: Thu Jan 01 00:00:07 1970 +0000 +summary: Adding c branch +