636 close_fds=util.closefds, |
636 close_fds=util.closefds, |
637 stdout=subprocess.PIPE) |
637 stdout=subprocess.PIPE) |
638 if stream: |
638 if stream: |
639 return p.stdout, None |
639 return p.stdout, None |
640 |
640 |
641 retdata = p.stdout.read() |
641 retdata = p.stdout.read().strip() |
642 # wait for the child to exit to avoid race condition. |
642 # wait for the child to exit to avoid race condition. |
643 p.wait() |
643 p.wait() |
644 |
644 |
645 if p.returncode != 0: |
645 if p.returncode != 0: |
646 # there are certain error codes that are ok |
646 # there are certain error codes that are ok |
657 raise util.Abort('git %s error %d' % (command, p.returncode)) |
657 raise util.Abort('git %s error %d' % (command, p.returncode)) |
658 |
658 |
659 return retdata, p.returncode |
659 return retdata, p.returncode |
660 |
660 |
661 def _gitstate(self): |
661 def _gitstate(self): |
662 return self._gitcommand(['rev-parse', 'HEAD']).strip() |
662 return self._gitcommand(['rev-parse', 'HEAD']) |
663 |
663 |
664 def _githavelocally(self, revision): |
664 def _githavelocally(self, revision): |
665 out, code = self._gitdir(['cat-file', '-e', revision]) |
665 out, code = self._gitdir(['cat-file', '-e', revision]) |
666 return code == 0 |
666 return code == 0 |
667 |
667 |
668 def _gitisancestor(self, r1, r2): |
668 def _gitisancestor(self, r1, r2): |
669 base = self._gitcommand(['merge-base', r1, r2]).strip() |
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 the current branch and a map from git revision to branch[es]' |
674 bm = {} |
674 bm = {} |
675 redirects = {} |
675 redirects = {} |
676 current = None |
676 current = None |
677 out = self._gitcommand(['branch', '-a', '--no-color', |
677 out = self._gitcommand(['branch', '-a', '--no-color', |
678 '--verbose', '--abbrev=40']) |
678 '--verbose', '--abbrev=40']) |
679 for line in out.split('\n'): |
679 for line in out.split('\n'): |
680 if not line: |
|
681 continue |
|
682 if line[2:].startswith('(no branch)'): |
680 if line[2:].startswith('(no branch)'): |
683 continue |
681 continue |
684 branch, revision = line[2:].split()[:2] |
682 branch, revision = line[2:].split()[:2] |
685 if revision == '->': |
683 if revision == '->': |
686 continue # ignore remote/HEAD redirects |
684 continue # ignore remote/HEAD redirects |
706 return True |
704 return True |
707 # check for staged changes or modified files; ignore untracked files |
705 # check for staged changes or modified files; ignore untracked files |
708 # docs say --porcelain flag is future-proof format |
706 # docs say --porcelain flag is future-proof format |
709 changed = self._gitcommand(['status', '--porcelain', |
707 changed = self._gitcommand(['status', '--porcelain', |
710 '--untracked-files=no']) |
708 '--untracked-files=no']) |
711 return bool(changed.strip()) |
709 return bool(changed) |
712 |
710 |
713 def get(self, state): |
711 def get(self, state): |
714 source, revision, kind = state |
712 source, revision, kind = state |
715 self._fetch(source, revision) |
713 self._fetch(source, revision) |
716 # if the repo was set to be bare, unbare it |
714 # if the repo was set to be bare, unbare it |
717 if self._gitcommand(['config', '--get', 'core.bare'] |
715 if self._gitcommand(['config', '--bool', 'core.bare']) == 'true': |
718 ).strip() == 'true': |
|
719 self._gitcommand(['config', 'core.bare', 'false']) |
716 self._gitcommand(['config', 'core.bare', 'false']) |
720 if self._gitstate() == revision: |
717 if self._gitstate() == revision: |
721 self._gitcommand(['reset', '--hard', 'HEAD']) |
718 self._gitcommand(['reset', '--hard', 'HEAD']) |
722 return |
719 return |
723 elif self._gitstate() == revision: |
720 elif self._gitstate() == revision: |
761 return self._gitstate() |
758 return self._gitstate() |
762 |
759 |
763 def merge(self, state): |
760 def merge(self, state): |
764 source, revision, kind = state |
761 source, revision, kind = state |
765 self._fetch(source, revision) |
762 self._fetch(source, revision) |
766 base = self._gitcommand(['merge-base', revision, |
763 base = self._gitcommand(['merge-base', revision, self._state[1]]) |
767 self._state[1]]).strip() |
|
768 if base == revision: |
764 if base == revision: |
769 self.get(state) # fast forward merge |
765 self.get(state) # fast forward merge |
770 elif base != self._state[1]: |
766 elif base != self._state[1]: |
771 self._gitcommand(['merge', '--no-commit', revision]) |
767 self._gitcommand(['merge', '--no-commit', revision]) |
772 |
768 |