diff options
author | Shawn O. Pearce <sop@google.com> | 2009-04-18 15:04:41 -0700 |
---|---|---|
committer | Shawn O. Pearce <sop@google.com> | 2009-04-18 15:04:41 -0700 |
commit | 89e717d9481c0c69292a39f85599f5df8277b004 (patch) | |
tree | 1fc613edd34eb349b673505b872be21a416ab52f | |
parent | 0f0dfa3930bc16078ef0b1a00ff6849333038fc7 (diff) | |
download | git-repo-89e717d9481c0c69292a39f85599f5df8277b004.tar.gz |
Improve checkout performance for the common unmodified case
Most projects will have their branch heads matching in all branches,
so switching between them should be just a matter of updating the
work tree's HEAD symref. This can be done in pure Python, saving
quite a bit of time over forking 'git checkout'.
Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r-- | project.py | 43 | ||||
-rw-r--r-- | subcmds/checkout.py | 31 | ||||
-rw-r--r-- | subcmds/start.py | 5 |
3 files changed, 56 insertions, 23 deletions
@@ -779,9 +779,8 @@ class Project(object): | |||
779 | 779 | ||
780 | all = self.bare_ref.all | 780 | all = self.bare_ref.all |
781 | if (R_HEADS + name) in all: | 781 | if (R_HEADS + name) in all: |
782 | cmd = ['checkout', name, '--'] | ||
783 | return GitCommand(self, | 782 | return GitCommand(self, |
784 | cmd, | 783 | ['checkout', name, '--'], |
785 | capture_stdout = True, | 784 | capture_stdout = True, |
786 | capture_stderr = True).Wait() == 0 | 785 | capture_stderr = True).Wait() == 0 |
787 | 786 | ||
@@ -815,9 +814,8 @@ class Project(object): | |||
815 | branch.Save() | 814 | branch.Save() |
816 | return True | 815 | return True |
817 | 816 | ||
818 | cmd = ['checkout', '-b', branch.name, rev] | ||
819 | if GitCommand(self, | 817 | if GitCommand(self, |
820 | cmd, | 818 | ['checkout', '-b', branch.name, rev], |
821 | capture_stdout = True, | 819 | capture_stdout = True, |
822 | capture_stderr = True).Wait() == 0: | 820 | capture_stderr = True).Wait() == 0: |
823 | branch.Save() | 821 | branch.Save() |
@@ -827,16 +825,39 @@ class Project(object): | |||
827 | def CheckoutBranch(self, name): | 825 | def CheckoutBranch(self, name): |
828 | """Checkout a local topic branch. | 826 | """Checkout a local topic branch. |
829 | """ | 827 | """ |
828 | rev = R_HEADS + name | ||
829 | head = self.work_git.GetHead() | ||
830 | if head == rev: | ||
831 | # Already on the branch | ||
832 | # | ||
833 | return True | ||
830 | 834 | ||
831 | # Be sure the branch exists | 835 | all = self.bare_ref.all |
832 | try: | 836 | try: |
833 | tip_rev = self.bare_git.rev_parse(R_HEADS + name) | 837 | revid = all[rev] |
834 | except GitError: | 838 | except KeyError: |
835 | return False; | 839 | # Branch does not exist in this project |
840 | # | ||
841 | return False | ||
842 | |||
843 | if head.startswith(R_HEADS): | ||
844 | try: | ||
845 | head = all[head] | ||
846 | except KeyError: | ||
847 | head = None | ||
848 | |||
849 | if head == revid: | ||
850 | # Same revision; just update HEAD to point to the new | ||
851 | # target branch, but otherwise take no other action. | ||
852 | # | ||
853 | _lwrite(os.path.join(self.worktree, '.git', HEAD), | ||
854 | 'ref: %s%s\n' % (R_HEADS, name)) | ||
855 | return True | ||
836 | 856 | ||
837 | # Do the checkout | 857 | return GitCommand(self, |
838 | cmd = ['checkout', name, '--'] | 858 | ['checkout', name, '--'], |
839 | return GitCommand(self, cmd).Wait() == 0 | 859 | capture_stdout = True, |
860 | capture_stderr = True).Wait() == 0 | ||
840 | 861 | ||
841 | def AbandonBranch(self, name): | 862 | def AbandonBranch(self, name): |
842 | """Destroy a local topic branch. | 863 | """Destroy a local topic branch. |
diff --git a/subcmds/checkout.py b/subcmds/checkout.py index 07644c95..4198acd1 100644 --- a/subcmds/checkout.py +++ b/subcmds/checkout.py | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | import sys | 16 | import sys |
17 | from command import Command | 17 | from command import Command |
18 | from progress import Progress | ||
18 | 19 | ||
19 | class Checkout(Command): | 20 | class Checkout(Command): |
20 | common = True | 21 | common = True |
@@ -35,13 +36,23 @@ The command is equivalent to: | |||
35 | if not args: | 36 | if not args: |
36 | self.Usage() | 37 | self.Usage() |
37 | 38 | ||
38 | retValue = 0; | 39 | nb = args[0] |
39 | 40 | err = [] | |
40 | branch = args[0] | 41 | all = self.GetProjects(args[1:]) |
41 | for project in self.GetProjects(args[1:]): | 42 | |
42 | if not project.CheckoutBranch(branch): | 43 | pm = Progress('Checkout %s' % nb, len(all)) |
43 | retValue = 1; | 44 | for project in all: |
44 | print >>sys.stderr, "error: checking out branch '%s' in %s failed" % (branch, project.name) | 45 | pm.update() |
45 | 46 | if not project.CheckoutBranch(nb): | |
46 | if (retValue != 0): | 47 | err.append(project) |
47 | sys.exit(retValue); | 48 | pm.end() |
49 | |||
50 | if err: | ||
51 | if len(err) == len(all): | ||
52 | print >>sys.stderr, 'error: no project has branch %s' % nb | ||
53 | else: | ||
54 | for p in err: | ||
55 | print >>sys.stderr,\ | ||
56 | "error: %s/: cannot checkout %s" \ | ||
57 | % (p.relpath, nb) | ||
58 | sys.exit(1) | ||
diff --git a/subcmds/start.py b/subcmds/start.py index 49bb0e1a..8c74625f 100644 --- a/subcmds/start.py +++ b/subcmds/start.py | |||
@@ -49,7 +49,8 @@ revision specified in the manifest. | |||
49 | pm.end() | 49 | pm.end() |
50 | 50 | ||
51 | if err: | 51 | if err: |
52 | err.sort() | ||
53 | for p in err: | 52 | for p in err: |
54 | print >>sys.stderr, "error: cannot start in %s" % p.relpath | 53 | print >>sys.stderr,\ |
54 | "error: %s/: cannot start %s" \ | ||
55 | % (p.relpath, nb) | ||
55 | sys.exit(1) | 56 | sys.exit(1) |