--- a/mercurial/subrepo.py Sun Nov 14 18:22:33 2010 -0500
+++ b/mercurial/subrepo.py Sun Nov 14 18:31:29 2010 -0500
@@ -634,6 +634,26 @@
out, code = self._gitdir(['cat-file', '-e', revision])
return code == 0
+ def _gitbranchmap(self):
+ 'returns the current branch and a map from git revision to branch[es]'
+ bm = {}
+ redirects = {}
+ current = None
+ out = self._gitcommand(['branch', '-a', '--no-color',
+ '--verbose', '--abbrev=40'])
+ for line in out.split('\n'):
+ if not line:
+ continue
+ if line[2:].startswith('(no branch)'):
+ continue
+ branch, revision = line[2:].split()[:2]
+ if revision == '->':
+ continue # ignore remote/HEAD redirects
+ if line[0] == '*':
+ current = branch
+ bm.setdefault(revision, []).append(branch)
+ return current, bm
+
def _fetch(self, source, revision):
if not os.path.exists('%s/.git' % self._path):
self._ui.status(_('cloning subrepo %s\n') % self._relpath)
@@ -658,12 +678,32 @@
def get(self, state):
source, revision, kind = state
self._fetch(source, revision)
- if self._gitstate() != revision:
+ if self._gitstate() == revision:
+ return
+ current, bm = self._gitbranchmap()
+ if revision not in bm:
+ # no branch to checkout, check it out with no branch
self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
self._relpath)
self._ui.warn(_('check out a git branch if you intend '
'to make changes\n'))
self._gitcommand(['checkout', '-q', revision])
+ return
+ branches = bm[revision]
+ firstlocalbranch = None
+ for b in branches:
+ if b == 'master':
+ # master trumps all other branches
+ self._gitcommand(['checkout', 'master'])
+ return
+ if not firstlocalbranch and not b.startswith('remotes/'):
+ firstlocalbranch = b
+ if firstlocalbranch:
+ self._gitcommand(['checkout', firstlocalbranch])
+ else:
+ remote = branches[0]
+ local = remote.split('/')[-1]
+ self._gitcommand(['checkout', '-b', local, remote])
def commit(self, text, user, date):
cmd = ['commit', '-a', '-m', text]
@@ -692,10 +732,15 @@
cmd = ['push']
if force:
cmd.append('--force')
- # as subrepos have no notion of "where to push to" we
- # assume origin master. This is git's default
- self._gitcommand(cmd + ['origin', 'master', '-q'])
- return True
+ # push the currently checked out branch
+ current, bm = self._gitbranchmap()
+ if current:
+ 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)
+ return False
types = {
'hg': hgsubrepo,
--- a/tests/test-subrepo-git.t Sun Nov 14 18:22:33 2010 -0500
+++ b/tests/test-subrepo-git.t Sun Nov 14 18:31:29 2010 -0500
@@ -40,14 +40,19 @@
source ../gitroot
revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
-record a new commit from upstream
+record a new commit from upstream from a different branch
$ cd ../gitroot
+ $ git checkout -b testing
+ Switched to a new branch 'testing'
$ echo gg >> g
$ git commit -q -a -m gg
$ cd ../t/s
$ git pull -q
+ $ git checkout -b testing origin/testing
+ Switched to a new branch 'testing'
+ Branch testing set up to track remote branch testing from origin.
$ cd ..
$ hg commit -m 'update git subrepo'
@@ -72,8 +77,7 @@
update to previous substate
$ hg update 1
- checking out detached HEAD in subrepo s
- check out a git branch if you intend to make changes
+ Switched to a new branch 'master'
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cat s/g
g