668 def _gitisancestor(self, r1, r2): |
668 def _gitisancestor(self, r1, r2): |
669 base = self._gitcommand(['merge-base', r1, r2]) |
669 base = self._gitcommand(['merge-base', r1, r2]) |
670 return base == r1 |
670 return base == r1 |
671 |
671 |
672 def _gitbranchmap(self): |
672 def _gitbranchmap(self): |
673 'returns the current branch and a map from git revision to branch[es]' |
673 '''returns 3 things: |
674 bm = {} |
674 the current branch, |
675 redirects = {} |
675 a map from git branch to revision |
|
676 a map from revision to branches''' |
|
677 branch2rev = {} |
|
678 rev2branch = {} |
676 current = None |
679 current = None |
677 out = self._gitcommand(['branch', '-a', '--no-color', |
680 out = self._gitcommand(['branch', '-a', '--no-color', |
678 '--verbose', '--abbrev=40']) |
681 '--verbose', '--no-abbrev']) |
679 for line in out.split('\n'): |
682 for line in out.split('\n'): |
680 if line[2:].startswith('(no branch)'): |
683 if line[2:].startswith('(no branch)'): |
681 continue |
684 continue |
682 branch, revision = line[2:].split()[:2] |
685 branch, revision = line[2:].split()[:2] |
683 if revision == '->': |
686 if revision == '->': |
684 continue # ignore remote/HEAD redirects |
687 continue # ignore remote/HEAD redirects |
685 if line[0] == '*': |
688 if line[0] == '*': |
686 current = branch |
689 current = branch |
687 bm.setdefault(revision, []).append(branch) |
690 branch2rev[branch] = revision |
688 return current, bm |
691 rev2branch.setdefault(revision, []).append(branch) |
|
692 return current, branch2rev, rev2branch |
689 |
693 |
690 def _fetch(self, source, revision): |
694 def _fetch(self, source, revision): |
691 if not os.path.exists('%s/.git' % self._path): |
695 if not os.path.exists('%s/.git' % self._path): |
692 self._ui.status(_('cloning subrepo %s\n') % self._relpath) |
696 self._ui.status(_('cloning subrepo %s\n') % self._relpath) |
693 self._gitnodir(['clone', source, self._path]) |
697 self._gitnodir(['clone', source, self._path]) |
717 if self._gitstate() == revision: |
721 if self._gitstate() == revision: |
718 self._gitcommand(['reset', '--hard', 'HEAD']) |
722 self._gitcommand(['reset', '--hard', 'HEAD']) |
719 return |
723 return |
720 elif self._gitstate() == revision: |
724 elif self._gitstate() == revision: |
721 return |
725 return |
722 current, bm = self._gitbranchmap() |
726 current, branch2rev, rev2branch = self._gitbranchmap() |
723 if revision not in bm: |
727 if revision not in rev2branch: |
724 # no branch to checkout, check it out with no branch |
728 # no branch to checkout, check it out with no branch |
725 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') % |
729 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') % |
726 self._relpath) |
730 self._relpath) |
727 self._ui.warn(_('check out a git branch if you intend ' |
731 self._ui.warn(_('check out a git branch if you intend ' |
728 'to make changes\n')) |
732 'to make changes\n')) |
729 self._gitcommand(['checkout', '-q', revision]) |
733 self._gitcommand(['checkout', '-q', revision]) |
730 return |
734 return |
731 branches = bm[revision] |
735 branches = rev2branch[revision] |
732 firstlocalbranch = None |
736 firstlocalbranch = None |
733 for b in branches: |
737 for b in branches: |
734 if b == 'master': |
738 if b == 'master': |
735 # master trumps all other branches |
739 # master trumps all other branches |
736 self._gitcommand(['checkout', 'master']) |
740 self._gitcommand(['checkout', 'master']) |
766 elif base != self._state[1]: |
770 elif base != self._state[1]: |
767 self._gitcommand(['merge', '--no-commit', revision]) |
771 self._gitcommand(['merge', '--no-commit', revision]) |
768 |
772 |
769 def push(self, force): |
773 def push(self, force): |
770 # if a branch in origin contains the revision, nothing to do |
774 # if a branch in origin contains the revision, nothing to do |
771 current, bm = self._gitbranchmap() |
775 current, branch2rev, rev2branch = self._gitbranchmap() |
772 for revision, branches in bm.iteritems(): |
776 for b, revision in branch2rev.iteritems(): |
773 for b in branches: |
777 if b.startswith('remotes/origin'): |
774 if b.startswith('remotes/origin'): |
778 if self._gitisancestor(self._state[1], revision): |
775 if self._gitisancestor(self._state[1], revision): |
779 return True |
776 return True |
|
777 # otherwise, try to push the currently checked out branch |
780 # otherwise, try to push the currently checked out branch |
778 cmd = ['push'] |
781 cmd = ['push'] |
779 if force: |
782 if force: |
780 cmd.append('--force') |
783 cmd.append('--force') |
781 if current: |
784 if current: |