[PATCH] Deleting a named branch.
Govind Salinas
govind at sophiasuchtig.com
Mon Jan 21 20:13:47 CST 2008
# HG changeset patch
# User Govind Salinas <blix at sophiasuchtig.com>
# Date 1200967247 21600
# Node ID 7a01fea81b8d0f80fcd214104f538412bf2258eb
# Parent d39af2eabb8c8656c200ecc23d07faacf95be68c
Delete a branch and take any nodes not reachable from another head.
This is a patch for comment. Please take a look and let me know what
needs to be changed. I am neither very familiar with hg nor is python
my native language so I am sure there are instances where things could
be done better and more efficiently. I have a test which I have
passing which I will submit with the real patch. I also understand
that the code should be moved somewhere else, I am not sure if it
should go in localrepo or in repair.
Basic algorithm:
If you are on the branch you want to delete, bail. That leaves you in
a weird situation.
If the branch you want to delete doesn't exist, bail.
Get an orderd list of all the reachable commits for the branch to
delete (children before parents).
Accumulate a set of all the commits reachable from other branchheads.
The intersection of the two are places where a parent of the branch to
delete is reachable from another branch. These are the common
ancestors.
Go down the ordered list of commits to the branch to delete until you
find a common ancestor. The commit previous to this is the last
commit you can delete.
use repair to strip the commits from the limit onwards.
diff -r d39af2eabb8c -r 7a01fea81b8d mercurial/cmdutil.py
--- a/mercurial/cmdutil.py Fri Jan 18 10:48:25 2008 -0600
+++ b/mercurial/cmdutil.py Mon Jan 21 20:00:47 2008 -0600
@@ -761,7 +761,7 @@ class changeset_templater(changeset_prin
branch = changes[5].get("branch")
if branch != 'default':
branch = util.tolocal(branch)
- return showlist('branch', [branch], plural='branches', **args)
+ return showlist('branch', [branch], plural='branches', **args)
def showparents(**args):
parents = [[('rev', p), ('node', hex(log.node(p)))]
diff -r d39af2eabb8c -r 7a01fea81b8d mercurial/commands.py
--- a/mercurial/commands.py Fri Jan 18 10:48:25 2008 -0600
+++ b/mercurial/commands.py Mon Jan 21 20:00:47 2008 -0600
@@ -11,7 +11,7 @@ import hg, util, revlog, bundlerepo, ext
import hg, util, revlog, bundlerepo, extensions
import difflib, patch, time, help, mdiff, tempfile
import errno, version, socket
-import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
+import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect, repair
# Commands start here, listed alphabetically
@@ -342,6 +342,51 @@ def branch(ui, repo, label=None, **opts)
"""
if label:
+ if opts.get('delete'):
+ if repo.dirstate.branch() == label:
+ raise util.Abort(_('cannot delete current branch\n'))
+ if label not in repo.branchtags():
+ raise util.Abort(_('%s is not a valid branch name\n') % label)
+
+
+ changelog = repo.changelog
+ branchnodes = repo.branchnodes()
+
+ branchtodelete = repo.lookup(label)
+ branchancestors = [branchtodelete]
+
+ idx = 0
+ while (idx < len(branchancestors)):
+ commit = branchancestors[idx]
+ for p in changelog.parents(commit):
+ if p != nullid and p not in branchancestors:
+ branchancestors.insert(idx + 1, p)
+ idx += 1
+
+ others = set()
+
+ for branch in branchnodes:
+ if branch != branchtodelete:
+ others = others.union(changelog.reachable(branch))
+
+ commonancestors = others.intersection(branchancestors)
+
+ prunelimit = None
+ for commit in branchancestors:
+ if commit in commonancestors:
+ break
+ prunelimit = commit
+ else:
+ prunelimit = None
+
+ if prunelimit:
+ repair.strip(ui, repo, prunelimit, None)
+ repo.invalidate()
+ if label not in repo.branchtags():
+ ui.status(_('branch %s deleted\n') % label)
+ else:
+ util.Abort(_('unable to delete %s') % label)
+ return
if not opts.get('force') and label in repo.branchtags():
if label not in [p.branch() for p in repo.workingctx().parents()]:
raise util.Abort(_('a branch of the same name already exists'
@@ -2754,7 +2799,9 @@ table = {
"branch":
(branch,
[('f', 'force', None,
- _('set branch name even if it shadows an existing branch'))],
+ _('set branch name even if it shadows an existing branch')),
+ ('d', 'delete', None,
+ _('remove branch and unreachable history'))],
_('hg branch [-f] [NAME]')),
"branches":
(branches,
diff -r d39af2eabb8c -r 7a01fea81b8d mercurial/localrepo.py
--- a/mercurial/localrepo.py Fri Jan 18 10:48:25 2008 -0600
+++ b/mercurial/localrepo.py Mon Jan 21 20:00:47 2008 -0600
@@ -290,6 +290,13 @@ class localrepository(repo.repository):
self.tags()
return self._tagstypecache.get(tagname)
+
+ def branchnodes(self):
+ branches = self.branchtags()
+ nodes = set()
+ for b in branches:
+ nodes.add(self.changectx(b).node())
+ return nodes
def _hgtagsnodes(self):
heads = self.heads()
@@ -579,6 +586,7 @@ class localrepository(repo.repository):
self.tagscache = None
self._tagstypecache = None
self.nodetagscache = None
+ self.branchcache = None
def _lock(self, lockname, wait, releasefn, acquirefn, desc):
try:
More information about the Mercurial-devel
mailing list