diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -446,8 +446,12 @@ def branches(ui, repo, active=False): """ hexfunc = ui.debugflag and hex or short activebranches = [encoding.tolocal(repo[n].branch()) - for n in repo.heads(closed=False)] - branches = sorted([(tag in activebranches, repo.changelog.rev(node), tag) + for n in repo.heads()] + def testactive(tag, node): + realhead = tag in activebranches + open = node in repo.branchheads(tag, closed=False) + return realhead and open + branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag) for tag, node in repo.branchtags().items()], reverse=True) @@ -1302,17 +1306,22 @@ def heads(ui, repo, *branchrevs, **opts) With no arguments, show all repository head changesets. - If branch names or revisions 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 a given branch takes place. + If one or more REV is given, the "branch heads" will be shown for + the named branch associated with that revision. The name of the + branch is called the revision's branch tag. + + Branch heads are revisions on a given named branch that do not have + any children on the same branch. A branch head could be a true head + or it could be the last changeset on a branch before a new branch + was created. If none of the branch heads are true heads, the branch + is considered inactive. + + If STARTREV is specified only those heads (or branch heads) that + are descendants of STARTREV will be displayed. """ if opts.get('rev'): start = repo.lookup(opts['rev']) @@ -1322,10 +1331,10 @@ def heads(ui, repo, *branchrevs, **opts) hideinactive, _heads = opts.get('active'), None if not branchrevs: # Assume we're looking repo-wide heads if no revs were specified. - heads = repo.heads(start, closed=closed) + heads = repo.heads(start) else: if hideinactive: - _heads = repo.heads(start, closed=closed) + _heads = repo.heads(start) heads = [] visitedset = set() for branchrev in branchrevs: @@ -1335,7 +1344,9 @@ def heads(ui, repo, *branchrevs, **opts) visitedset.add(branch) bheads = repo.branchheads(branch, start, closed=closed) if not bheads: - if branch != branchrev: + if not opts.get('rev'): + ui.warn(_("no open branch heads on branch %s\n") % branch) + elif branch != branchrev: ui.warn(_("no changes on branch %s containing %s are " "reachable from %s\n") % (branch, branchrev, opts.get('rev'))) @@ -3251,7 +3262,7 @@ table = { ('c', 'closed', False, _('show normal and closed heads')), ] + templateopts, - _('[-r REV] [REV]...')), + _('[-r STARTREV] [REV]...')), "help": (help_, [], _('[TOPIC]')), "identify|id": (identify, diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py +++ b/mercurial/hgweb/webcommands.py @@ -361,7 +361,7 @@ def tags(web, req, tmpl): def branches(web, req, tmpl): b = web.repo.branchtags() tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems()) - open = set(web.repo[n].branch() for n in web.repo.heads(closed=False)) + heads = web.repo.heads() parity = paritygen(web.stripecount) sortkey = lambda ctx: ('close' not in ctx.extra(), ctx.rev()) @@ -371,7 +371,12 @@ def branches(web, req, tmpl): if limit > 0 and count >= limit: return count += 1 - status = ctx.branch() in open and 'open' or 'closed' + if ctx.node() not in heads: + status = 'inactive' + elif not web.repo.branchheads(ctx.branch()): + status = 'closed' + else: + status = 'open' yield {'parity': parity.next(), 'branch': ctx.branch(), 'status': status, diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1134,15 +1134,10 @@ class localrepository(repo.repository): finally: wlock.release() - def heads(self, start=None, closed=False): + def heads(self, start=None): heads = self.changelog.heads(start) - def display(head): - if closed: - return True - extras = self.changelog.read(head)[5] - return ('close' not in extras) # sort the output in rev descending order - heads = [(-self.changelog.rev(h), h) for h in heads if display(h)] + heads = [(-self.changelog.rev(h), h) for h in heads] return [n for (r, n) in sorted(heads)] def branchheads(self, branch=None, start=None, closed=False): diff --git a/tests/test-branches b/tests/test-branches --- a/tests/test-branches +++ b/tests/test-branches @@ -71,9 +71,19 @@ hg commit -d '9 0' --close-branch -m 'cl echo '--- b branch should be inactive' hg branches hg branches -a +hg heads b +hg heads --closed b echo 'xxx4' >> b hg commit -d '9 0' -m 'reopen branch with a change' echo '--- branch b is back in action' hg branches -a -hg heads -c +echo '---- test heads listings' hg heads +echo '% branch default' +hg heads default +echo '% branch a' +hg heads a +hg heads --active a +echo '% branch b' +hg heads b +hg heads --closed b diff --git a/tests/test-branches.out b/tests/test-branches.out --- a/tests/test-branches.out +++ b/tests/test-branches.out @@ -113,9 +113,25 @@ c 6:589736a a 5:d8cbc61dbaa6 (inactive) default 0:19709c5a4e75 (inactive) a branch name much longer than the default justification used by branches 7:10ff5895aa57 +no open branch heads on branch b +changeset: 12:2da6583810df +branch: b +tag: tip +parent: 8:eebb944467c9 +user: test +date: Thu Jan 01 00:00:09 1970 +0000 +summary: close this part branch too + +changeset: 11:c84627f3c15d +branch: b +user: test +date: Thu Jan 01 00:00:09 1970 +0000 +summary: prune bad branch + --- branch b is back in action b 13:6ac12926b8c3 a branch name much longer than the default justification used by branches 7:10ff5895aa57 +---- test heads listings changeset: 13:6ac12926b8c3 branch: b tag: tip @@ -135,6 +151,21 @@ user: test date: Thu Jan 01 00:00:06 1970 +0000 summary: Adding d branch +% branch default +changeset: 0:19709c5a4e75 +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: Adding root node + +% branch a +changeset: 5:d8cbc61dbaa6 +branch: a +parent: 2:881fe2b92ad0 +user: test +date: Thu Jan 01 00:00:04 1970 +0000 +summary: Adding b branch head 2 + +% branch b changeset: 13:6ac12926b8c3 branch: b tag: tip @@ -142,9 +173,16 @@ user: test date: Thu Jan 01 00:00:09 1970 +0000 summary: reopen branch with a change -changeset: 7:10ff5895aa57 -branch: a branch name much longer than the default justification used by branches +changeset: 13:6ac12926b8c3 +branch: b +tag: tip user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Adding d branch +date: Thu Jan 01 00:00:09 1970 +0000 +summary: reopen branch with a change +changeset: 11:c84627f3c15d +branch: b +user: test +date: Thu Jan 01 00:00:09 1970 +0000 +summary: prune bad branch + diff --git a/tests/test-hgweb-commands.out b/tests/test-hgweb-commands.out --- a/tests/test-hgweb-commands.out +++ b/tests/test-hgweb-commands.out @@ -532,7 +532,7 @@ branches | many years ago a4f92ed23982 -default +default changeset | changelog |