[PATCH 2 of 2] subrepo: implement 'unshare' for Mercurial subrepos

Matt Harbison mharbison72 at gmail.com
Wed Oct 18 00:12:39 EDT 2017


# HG changeset patch
# User Matt Harbison <matt_harbison at yahoo.com>
# Date 1508295333 14400
#      Tue Oct 17 22:55:33 2017 -0400
# Node ID 609c60c0b706f9b6402d275a57b8255b142e8ba7
# Parent  a6b470f15cc5f902afd54f29b0e53e5c03f6eec6
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 @@
     # 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 @@
     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 @@
     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 -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


More information about the Mercurial-devel mailing list