diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -645,6 +645,9 @@ coreconfigitem('experimental', 'server.s coreconfigitem('experimental', 'single-head-per-branch', default=False, ) +coreconfigitem('experimental', 'single-head-per-branch:account-closed-heads', + default=False, +) coreconfigitem('experimental', 'sshserver.support-v2', default=False, ) diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1920,8 +1920,13 @@ class localrepository(object): # gating. tracktags(tr2) repo = reporef() - if repo.ui.configbool('experimental', 'single-head-per-branch'): - scmutil.enforcesinglehead(repo, tr2, desc) + + r = repo.ui.configsuboptions('experimental', + 'single-head-per-branch') + singlehead, singleheadsub = r + if singlehead: + accountclosed = singleheadsub.get("account-closed-heads", False) + scmutil.enforcesinglehead(repo, tr2, desc, accountclosed) if hook.hashook(repo.ui, 'pretxnclose-bookmark'): for name, (old, new) in sorted(tr.changes['bookmarks'].items()): args = tr.hookargs.copy() diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -1895,14 +1895,16 @@ def nodesummaries(repo, nodes, maxnumnod first = ' '.join(short(h) for h in nodes[:maxnumnodes]) return _("%s and %d others") % (first, len(nodes) - maxnumnodes) -def enforcesinglehead(repo, tr, desc): +def enforcesinglehead(repo, tr, desc, accountclosed=False): """check that no named branch has multiple heads""" if desc in ('strip', 'repair'): # skip the logic during strip return visible = repo.filtered('visible') # possible improvement: we could restrict the check to affected branch - for name, heads in visible.branchmap().iteritems(): + bm = visible.branchmap() + for name in bm: + heads = bm.branchheads(name, closed=accountclosed) if len(heads) > 1: msg = _('rejecting multiple heads on branch "%s"') msg %= name diff --git a/tests/test-single-head.t b/tests/test-single-head.t --- a/tests/test-single-head.t +++ b/tests/test-single-head.t @@ -200,3 +200,62 @@ actual stripping $ hg strip --config extensions.strip= --rev 'desc("c_dH0")' saved backup bundle to $TESTTMP/client/.hg/strip-backup/fe47ea669cea-a41bf5a9-backup.hg +Test that closing heads are ignored by default +----------------------------------------------- + + $ hg up 'desc("c_aG0")' + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ mkcommit c_aJ0 + created new head + +pushing the new head should fails + + $ hg push -f + pushing to $TESTTMP/single-head-server + searching for changes + adding changesets + adding manifests + adding file changes + transaction abort! + rollback completed + abort: rejecting multiple heads on branch "branch_A" + (2 heads: 49003e504178 468bd81ccc5d) + [255] + + +closing the head and pushing should succeed + + $ mkcommit c_aK0 --close-branch + $ hg push -f + pushing to $TESTTMP/single-head-server + searching for changes + adding changesets + adding manifests + adding file changes + added 4 changesets with 4 changes to 4 files (-1 heads) + + +Test that closing heads can be explicitly accounted for +------------------------------------------------------- + + $ cat <> $TESTTMP/single-head-server/.hg/hgrc + > [experimental] + > single-head-per-branch:account-closed-heads = yes + > EOF + + $ hg up 'desc("c_aG0")' + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ mkcommit c_aL0 + created new head + $ mkcommit c_aM0 --close-branch + $ hg push -f + pushing to $TESTTMP/single-head-server + searching for changes + adding changesets + adding manifests + adding file changes + transaction abort! + rollback completed + abort: rejecting multiple heads on branch "branch_A" + (3 heads: 49003e504178 5254bcccab93 42b9fe70a3c1) + [255]