mercurial/subrepo.py
changeset 13152 70d80907e4b8
parent 13151 519ac79d680b
child 13153 dca5488f0e4f
equal deleted inserted replaced
13151:519ac79d680b 13152:70d80907e4b8
   658         return retdata, p.returncode
   658         return retdata, p.returncode
   659 
   659 
   660     def _gitstate(self):
   660     def _gitstate(self):
   661         return self._gitcommand(['rev-parse', 'HEAD'])
   661         return self._gitcommand(['rev-parse', 'HEAD'])
   662 
   662 
       
   663     def _gitcurrentbranch(self):
       
   664         current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
       
   665         if err:
       
   666             current = None
       
   667         return current
       
   668 
   663     def _githavelocally(self, revision):
   669     def _githavelocally(self, revision):
   664         out, code = self._gitdir(['cat-file', '-e', revision])
   670         out, code = self._gitdir(['cat-file', '-e', revision])
   665         return code == 0
   671         return code == 0
   666 
   672 
   667     def _gitisancestor(self, r1, r2):
   673     def _gitisancestor(self, r1, r2):
   668         base = self._gitcommand(['merge-base', r1, r2])
   674         base = self._gitcommand(['merge-base', r1, r2])
   669         return base == r1
   675         return base == r1
   670 
   676 
   671     def _gitbranchmap(self):
   677     def _gitbranchmap(self):
   672         '''returns 3 things:
   678         '''returns 3 things:
   673         the current branch,
       
   674         a map from git branch to revision
   679         a map from git branch to revision
   675         a map from revision to branches'''
   680         a map from revision to branches
       
   681         a map from remote branch to local tracking branch'''
   676         branch2rev = {}
   682         branch2rev = {}
   677         rev2branch = {}
   683         rev2branch = {}
   678         tracking = {}
   684         tracking = {}
   679         current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
       
   680         if err:
       
   681             current = None
       
   682 
       
   683         out = self._gitcommand(['for-each-ref', '--format',
   685         out = self._gitcommand(['for-each-ref', '--format',
   684                                 '%(objectname) %(refname) %(upstream) end'])
   686                                 '%(objectname) %(refname) %(upstream) end'])
   685         for line in out.split('\n'):
   687         for line in out.split('\n'):
   686             revision, ref, upstream = line.split(' ')[:3]
   688             revision, ref, upstream = line.split(' ')[:3]
   687             if ref.startswith('refs/tags/'):
   689             if ref.startswith('refs/tags/'):
   691             branch2rev[ref] = revision
   693             branch2rev[ref] = revision
   692             rev2branch.setdefault(revision, []).append(ref)
   694             rev2branch.setdefault(revision, []).append(ref)
   693             if upstream:
   695             if upstream:
   694                 # assumes no more than one local tracking branch for a remote
   696                 # assumes no more than one local tracking branch for a remote
   695                 tracking[upstream] = ref
   697                 tracking[upstream] = ref
   696         return current, branch2rev, rev2branch, tracking
   698         return branch2rev, rev2branch, tracking
   697 
   699 
   698     def _fetch(self, source, revision):
   700     def _fetch(self, source, revision):
   699         if not os.path.exists('%s/.git' % self._path):
   701         if not os.path.exists('%s/.git' % self._path):
   700             self._ui.status(_('cloning subrepo %s\n') % self._relpath)
   702             self._ui.status(_('cloning subrepo %s\n') % self._relpath)
   701             self._gitnodir(['clone', source, self._path])
   703             self._gitnodir(['clone', source, self._path])
   729             if self._gitstate() == revision:
   731             if self._gitstate() == revision:
   730                 self._gitcommand(['reset', '--hard', 'HEAD'])
   732                 self._gitcommand(['reset', '--hard', 'HEAD'])
   731                 return
   733                 return
   732         elif self._gitstate() == revision:
   734         elif self._gitstate() == revision:
   733             return
   735             return
   734         current, branch2rev, rev2branch, tracking = self._gitbranchmap()
   736         branch2rev, rev2branch, tracking = self._gitbranchmap()
   735 
   737 
   736         def rawcheckout():
   738         def rawcheckout():
   737             # no branch to checkout, check it out with no branch
   739             # no branch to checkout, check it out with no branch
   738             self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
   740             self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
   739                           self._relpath)
   741                           self._relpath)
   774             # if the local tracking branch is downstream of it,
   776             # if the local tracking branch is downstream of it,
   775             # a normal `git pull` would have performed a "fast-forward merge"
   777             # a normal `git pull` would have performed a "fast-forward merge"
   776             # which is equivalent to updating the local branch to the remote.
   778             # which is equivalent to updating the local branch to the remote.
   777             # Since we are only looking at branching at update, we need to
   779             # Since we are only looking at branching at update, we need to
   778             # detect this situation and perform this action lazily.
   780             # detect this situation and perform this action lazily.
   779             if tracking[remote] != current:
   781             if tracking[remote] != self._gitcurrentbranch():
   780                 self._gitcommand(['checkout', tracking[remote]])
   782                 self._gitcommand(['checkout', tracking[remote]])
   781             self._gitcommand(['merge', '--ff', remote])
   783             self._gitcommand(['merge', '--ff', remote])
   782         else:
   784         else:
   783             # a real merge would be required, just checkout the revision
   785             # a real merge would be required, just checkout the revision
   784             rawcheckout()
   786             rawcheckout()
   807         elif base != self._state[1]:
   809         elif base != self._state[1]:
   808             self._gitcommand(['merge', '--no-commit', revision])
   810             self._gitcommand(['merge', '--no-commit', revision])
   809 
   811 
   810     def push(self, force):
   812     def push(self, force):
   811         # if a branch in origin contains the revision, nothing to do
   813         # if a branch in origin contains the revision, nothing to do
   812         current, branch2rev, rev2branch, tracking = self._gitbranchmap()
   814         branch2rev, rev2branch, tracking = self._gitbranchmap()
   813         if self._state[1] in rev2branch:
   815         if self._state[1] in rev2branch:
   814             for b in rev2branch[self._state[1]]:
   816             for b in rev2branch[self._state[1]]:
   815                 if b.startswith('refs/remotes/origin/'):
   817                 if b.startswith('refs/remotes/origin/'):
   816                     return True
   818                     return True
   817         for b, revision in branch2rev.iteritems():
   819         for b, revision in branch2rev.iteritems():
   820                     return True
   822                     return True
   821         # otherwise, try to push the currently checked out branch
   823         # otherwise, try to push the currently checked out branch
   822         cmd = ['push']
   824         cmd = ['push']
   823         if force:
   825         if force:
   824             cmd.append('--force')
   826             cmd.append('--force')
       
   827 
       
   828         current = self._gitcurrentbranch()
   825         if current:
   829         if current:
   826             # determine if the current branch is even useful
   830             # determine if the current branch is even useful
   827             if not self._gitisancestor(self._state[1], current):
   831             if not self._gitisancestor(self._state[1], current):
   828                 self._ui.warn(_('unrelated git branch checked out '
   832                 self._ui.warn(_('unrelated git branch checked out '
   829                                 'in subrepo %s\n') % self._relpath)
   833                                 'in subrepo %s\n') % self._relpath)