689 current = branch |
689 current = branch |
690 branch2rev[branch] = revision |
690 branch2rev[branch] = revision |
691 rev2branch.setdefault(revision, []).append(branch) |
691 rev2branch.setdefault(revision, []).append(branch) |
692 return current, branch2rev, rev2branch |
692 return current, branch2rev, rev2branch |
693 |
693 |
|
694 def _gittracking(self, branches): |
|
695 'return map of remote branch to local tracking branch' |
|
696 # assumes no more than one local tracking branch for each remote |
|
697 tracking = {} |
|
698 for b in branches: |
|
699 if b.startswith('remotes/'): |
|
700 continue |
|
701 remote = self._gitcommand(['config', 'branch.%s.remote' % b]) |
|
702 if remote: |
|
703 ref = self._gitcommand(['config', 'branch.%s.merge' % b]) |
|
704 tracking['remotes/%s/%s' % (remote, ref.split('/')[-1])] = b |
|
705 return tracking |
|
706 |
694 def _fetch(self, source, revision): |
707 def _fetch(self, source, revision): |
695 if not os.path.exists('%s/.git' % self._path): |
708 if not os.path.exists('%s/.git' % self._path): |
696 self._ui.status(_('cloning subrepo %s\n') % self._relpath) |
709 self._ui.status(_('cloning subrepo %s\n') % self._relpath) |
697 self._gitnodir(['clone', source, self._path]) |
710 self._gitnodir(['clone', source, self._path]) |
698 if self._githavelocally(revision): |
711 if self._githavelocally(revision): |
722 self._gitcommand(['reset', '--hard', 'HEAD']) |
735 self._gitcommand(['reset', '--hard', 'HEAD']) |
723 return |
736 return |
724 elif self._gitstate() == revision: |
737 elif self._gitstate() == revision: |
725 return |
738 return |
726 current, branch2rev, rev2branch = self._gitbranchmap() |
739 current, branch2rev, rev2branch = self._gitbranchmap() |
727 if revision not in rev2branch: |
740 |
|
741 def rawcheckout(): |
728 # no branch to checkout, check it out with no branch |
742 # no branch to checkout, check it out with no branch |
729 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') % |
743 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') % |
730 self._relpath) |
744 self._relpath) |
731 self._ui.warn(_('check out a git branch if you intend ' |
745 self._ui.warn(_('check out a git branch if you intend ' |
732 'to make changes\n')) |
746 'to make changes\n')) |
733 self._gitcommand(['checkout', '-q', revision]) |
747 self._gitcommand(['checkout', '-q', revision]) |
|
748 |
|
749 if revision not in rev2branch: |
|
750 rawcheckout() |
734 return |
751 return |
735 branches = rev2branch[revision] |
752 branches = rev2branch[revision] |
736 firstlocalbranch = None |
753 firstlocalbranch = None |
737 for b in branches: |
754 for b in branches: |
738 if b == 'master': |
755 if b == 'master': |
741 return |
758 return |
742 if not firstlocalbranch and not b.startswith('remotes/'): |
759 if not firstlocalbranch and not b.startswith('remotes/'): |
743 firstlocalbranch = b |
760 firstlocalbranch = b |
744 if firstlocalbranch: |
761 if firstlocalbranch: |
745 self._gitcommand(['checkout', firstlocalbranch]) |
762 self._gitcommand(['checkout', firstlocalbranch]) |
746 else: |
763 return |
747 remote = branches[0] |
764 |
|
765 tracking = self._gittracking(branch2rev.keys()) |
|
766 # choose a remote branch already tracked if possible |
|
767 remote = branches[0] |
|
768 if remote not in tracking: |
|
769 for b in branches: |
|
770 if b in tracking: |
|
771 remote = b |
|
772 break |
|
773 |
|
774 if remote not in tracking: |
|
775 # create a new local tracking branch |
748 local = remote.split('/')[-1] |
776 local = remote.split('/')[-1] |
749 self._gitcommand(['checkout', '-b', local, remote]) |
777 self._gitcommand(['checkout', '-b', local, remote]) |
|
778 elif self._gitisancestor(branch2rev[tracking[remote]], remote): |
|
779 # When updating to a tracked remote branch, |
|
780 # if the local tracking branch is downstream of it, |
|
781 # a normal `git pull` would have performed a "fast-forward merge" |
|
782 # which is equivalent to updating the local branch to the remote. |
|
783 # Since we are only looking at branching at update, we need to |
|
784 # detect this situation and perform this action lazily. |
|
785 if tracking[remote] != current: |
|
786 self._gitcommand(['checkout', tracking[remote]]) |
|
787 self._gitcommand(['merge', '--ff', remote]) |
|
788 else: |
|
789 # a real merge would be required, just checkout the revision |
|
790 rawcheckout() |
750 |
791 |
751 def commit(self, text, user, date): |
792 def commit(self, text, user, date): |
752 cmd = ['commit', '-a', '-m', text] |
793 cmd = ['commit', '-a', '-m', text] |
753 if user: |
794 if user: |
754 cmd += ['--author', user] |
795 cmd += ['--author', user] |