# HG changeset patch # User Matt Harbison # Date 2017-10-18 02:55:33 # Node ID 7d51a7792f52c392a7f6887d43198930c66c88be # Parent 9f7ecc5bbc28e1262a8afadad8b5d78bf134a302 subrepo: implement 'unshare' for Mercurial subrepos I think there's a slight hole here in that a subrepo could be shared, removed from .hgsub, and then it's not part of context.substate (so not iterated over). But the push command has the same hole IIRC, and I think removing a subrepo is an edge case. The import hack is a copy/paste of subrepo.subrepo(). diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -286,6 +286,13 @@ def unshare(ui, repo): # update store, spath, svfs and sjoin of repo repo.unfiltered().__init__(repo.baseui, repo.root) + # TODO: figure out how to access subrepos that exist, but were previously + # removed from .hgsub + c = repo['.'] + subs = c.substate + for s in sorted(subs): + c.sub(s).unshare() + def postshare(sourcerepo, destrepo, bookmarks=True, defaultpath=None): """Called after a new shared repo is created. diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -621,6 +621,11 @@ class abstractsubrepo(object): def shortid(self, revid): return revid + def unshare(self): + ''' + convert this repository from shared to normal storage. + ''' + def verify(self): '''verify the integrity of the repository. Return 0 on success or warning, 1 on any error. @@ -1083,6 +1088,24 @@ class hgsubrepo(abstractsubrepo): def shortid(self, revid): return revid[:12] + @annotatesubrepoerror + def unshare(self): + # subrepo inherently violates our import layering rules + # because it wants to make repo objects from deep inside the stack + # so we manually delay the circular imports to not break + # scripts that don't use our demand-loading + global hg + from . import hg as h + hg = h + + # Nothing prevents a user from sharing in a repo, and then making that a + # subrepo. Alternately, the previous unshare attempt may have failed + # part way through. So recurse whether or not this layer is shared. + if self._repo.shared(): + self.ui.status(_("unsharing subrepo '%s'\n") % self._relpath) + + hg.unshare(self.ui, self._repo) + def verify(self): try: rev = self._state[1] diff --git a/tests/test-archive.t b/tests/test-archive.t --- a/tests/test-archive.t +++ b/tests/test-archive.t @@ -51,6 +51,24 @@ hg subrepos are shared into existence on $ hg -R clone1 update -C tip cloning subrepo subrepo from $TESTTMP/test/subrepo 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ find share2 | egrep 'sharedpath|00.+\.i' | sort + share2/.hg/sharedpath + share2/subrepo/.hg/sharedpath + $ hg -R share2 unshare + unsharing subrepo 'subrepo' + $ find share2 | egrep 'sharedpath|00.+\.i' | sort + share2/.hg/00changelog.i + share2/.hg/sharedpath.old + share2/.hg/store/00changelog.i + share2/.hg/store/00manifest.i + share2/subrepo/.hg/00changelog.i + share2/subrepo/.hg/sharedpath.old + share2/subrepo/.hg/store/00changelog.i + share2/subrepo/.hg/store/00manifest.i + $ hg -R share2/subrepo log -r tip -T compact + 1[tip] 559dcc9bfa65 1970-01-01 00:00 +0000 test + subrepo mod + $ rm -rf clone1 $ hg clone -qr 1 test clone1