[PATCH] subrepo: lazier git push logic

Eric Eisner ede at MIT.EDU
Sun Nov 21 21:04:11 CST 2010


# HG changeset patch
# User Eric Eisner <ede at mit.edu>
# Date 1290394851 18000
# Node ID eee1108ce55017590bac75cb71a42cccc3ab43a2
# Parent  da69a1597285fe25eeedab1a45869487773b715b
subrepo: lazier git push logic

Avoids calls to git push when the revision is already known to be
in the remote repository. Now, when using a read-only git subrepo,
git will never need to talk to its upstream repository.

diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -662,6 +662,10 @@ class gitsubrepo(object):
         out, code = self._gitdir(['cat-file', '-e', revision])
         return code == 0
 
+    def _gitisancestor(self, r1, r2):
+        base = self._gitcommand(['merge-base', r1, r2]).strip()
+        return base == r1
+
     def _gitbranchmap(self):
         'returns the current branch and a map from git revision to branch[es]'
         bm = {}
@@ -764,17 +768,31 @@ class gitsubrepo(object):
             self._gitcommand(['merge', '--no-commit', revision])
 
     def push(self, force):
+        # if a branch in origin contains the revision, nothing to do
+        current, bm = self._gitbranchmap()
+        for revision, branches in bm.iteritems():
+            for b in branches:
+                if b.startswith('remotes/origin'):
+                    if self._gitisancestor(self._state[1], revision):
+                        return True
+        # otherwise, try to push the currently checked out branch
         cmd = ['push']
         if force:
             cmd.append('--force')
-        # push the currently checked out branch
-        current, bm = self._gitbranchmap()
         if current:
+            # determine if the current branch is even useful
+            if not self._gitisancestor(self._state[1], current):
+                self._ui.warn(_('unrelated git branch checked out '
+                                'in subrepo %s\n') % self._relpath)
+                return False
+            self._ui.status(_('pushing branch %s of subrepo %s\n') %
+                            (current, self._relpath))
             self._gitcommand(cmd + ['origin', current, '-q'])
             return True
         else:
             self._ui.warn(_('no branch checked out in subrepo %s\n'
-                            'nothing to push') % self._relpath)
+                            'cannot push revision %s') %
+                          (self._relpath, self._state[1]))
             return False
 
     def remove(self):
diff --git a/tests/test-subrepo-git.t b/tests/test-subrepo-git.t
--- a/tests/test-subrepo-git.t
+++ b/tests/test-subrepo-git.t
@@ -134,6 +134,7 @@ user b push changes
 
   $ hg push
   pushing to $TESTTMP/t
+  pushing branch testing of subrepo s
   searching for changes
   adding changesets
   adding manifests
@@ -170,12 +171,44 @@ user a pulls, merges, commits
    revision f47b465e1bce645dbf37232a00574aa1546ca8d3
   $ hg push
   pushing to $TESTTMP/t
+  pushing branch testing of subrepo s
   searching for changes
   adding changesets
   adding manifests
   adding file changes
   added 2 changesets with 2 changes to 1 files
 
+make upstream git changes
+
+  $ cd ..
+  $ git clone -q gitroot gitclone
+  $ cd gitclone
+  $ echo ff >> f
+  $ git commit -q -a -m ff
+  $ echo fff >> f
+  $ git commit -q -a -m fff
+  $ git push -q origin testing
+
+make and push changes to hg without updating the subrepo
+
+  $ cd ../t
+  $ hg clone . ../td
+  updating to branch default
+  cloning subrepo s
+  checking out detached HEAD in subrepo s
+  check out a git branch if you intend to make changes
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd ../td
+  $ echo aa >> a
+  $ hg commit -m aa
+  $ hg push
+  pushing to $TESTTMP/t
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+
 update to a revision without the subrepo, keeping the local git repository
 
   $ cd ../t


More information about the Mercurial-devel mailing list