Mercurial > public > mercurial-scm > hg
comparison mercurial/subrepo.py @ 13152:70d80907e4b8
subrepo: defer determination of git's current branch
author | Eric Eisner <ede@mit.edu> |
---|---|
date | Tue, 14 Dec 2010 21:56:43 -0500 |
parents | 519ac79d680b |
children | dca5488f0e4f |
comparison
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) |