diff options
author | Shawn O. Pearce <sop@google.com> | 2009-04-18 14:45:51 -0700 |
---|---|---|
committer | Shawn O. Pearce <sop@google.com> | 2009-04-18 14:45:51 -0700 |
commit | accc56d82b902e7c7a22401db710958fcb1c7b58 (patch) | |
tree | 3c3d233fe188315df9d87ddc247672a92167a3f5 | |
parent | db45da12089bf131579d100ff7990cbc18d07325 (diff) | |
download | git-repo-accc56d82b902e7c7a22401db710958fcb1c7b58.tar.gz |
Speed up 'repo start' by removing some forks
Its quite common for most projects to be matching the current
manifest revision, as most developers only modify one or two projects
at any one time. We can speed up `repo start foo` (that impacts
the entire client) by performing most of the branch creation and
switch operations in pure Python, and thus avoid 4 forks per project.
Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r-- | git_config.py | 48 | ||||
-rw-r--r-- | project.py | 82 |
2 files changed, 104 insertions, 26 deletions
diff --git a/git_config.py b/git_config.py index 78069c5d..7aad80d2 100644 --- a/git_config.py +++ b/git_config.py | |||
@@ -57,6 +57,7 @@ class GitConfig(object): | |||
57 | self.file = file | 57 | self.file = file |
58 | self.defaults = defaults | 58 | self.defaults = defaults |
59 | self._cache_dict = None | 59 | self._cache_dict = None |
60 | self._section_dict = None | ||
60 | self._remotes = {} | 61 | self._remotes = {} |
61 | self._branches = {} | 62 | self._branches = {} |
62 | self._pickle = os.path.join( | 63 | self._pickle = os.path.join( |
@@ -168,6 +169,33 @@ class GitConfig(object): | |||
168 | self._branches[b.name] = b | 169 | self._branches[b.name] = b |
169 | return b | 170 | return b |
170 | 171 | ||
172 | def HasSection(self, section, subsection = ''): | ||
173 | """Does at least one key in section.subsection exist? | ||
174 | """ | ||
175 | try: | ||
176 | return subsection in self._sections[section] | ||
177 | except KeyError: | ||
178 | return False | ||
179 | |||
180 | @property | ||
181 | def _sections(self): | ||
182 | d = self._section_dict | ||
183 | if d is None: | ||
184 | d = {} | ||
185 | for name in self._cache.keys(): | ||
186 | p = name.split('.') | ||
187 | if 2 == len(p): | ||
188 | section = p[0] | ||
189 | subsect = '' | ||
190 | else: | ||
191 | section = p[0] | ||
192 | subsect = '.'.join(p[1:-1]) | ||
193 | if section not in d: | ||
194 | d[section] = set() | ||
195 | d[section].add(subsect) | ||
196 | self._section_dict = d | ||
197 | return d | ||
198 | |||
171 | @property | 199 | @property |
172 | def _cache(self): | 200 | def _cache(self): |
173 | if self._cache_dict is None: | 201 | if self._cache_dict is None: |
@@ -443,11 +471,23 @@ class Branch(object): | |||
443 | def Save(self): | 471 | def Save(self): |
444 | """Save this branch back into the configuration. | 472 | """Save this branch back into the configuration. |
445 | """ | 473 | """ |
446 | self._Set('merge', self.merge) | 474 | if self._config.HasSection('branch', self.name): |
447 | if self.remote: | 475 | if self.remote: |
448 | self._Set('remote', self.remote.name) | 476 | self._Set('remote', self.remote.name) |
477 | else: | ||
478 | self._Set('remote', None) | ||
479 | self._Set('merge', self.merge) | ||
480 | |||
449 | else: | 481 | else: |
450 | self._Set('remote', None) | 482 | fd = open(self._config.file, 'ab') |
483 | try: | ||
484 | fd.write('[branch "%s"]\n' % self.name) | ||
485 | if self.remote: | ||
486 | fd.write('\tremote = %s\n' % self.remote.name) | ||
487 | if self.merge: | ||
488 | fd.write('\tmerge = %s\n' % self.merge) | ||
489 | finally: | ||
490 | fd.close() | ||
451 | 491 | ||
452 | def _Set(self, key, value): | 492 | def _Set(self, key, value): |
453 | key = 'branch.%s.%s' % (self.name, key) | 493 | key = 'branch.%s.%s' % (self.name, key) |
@@ -30,6 +30,21 @@ from remote import Remote | |||
30 | 30 | ||
31 | from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M | 31 | from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M |
32 | 32 | ||
33 | def _lwrite(path, content): | ||
34 | lock = '%s.lock' % path | ||
35 | |||
36 | fd = open(lock, 'wb') | ||
37 | try: | ||
38 | fd.write(content) | ||
39 | finally: | ||
40 | fd.close() | ||
41 | |||
42 | try: | ||
43 | os.rename(lock, path) | ||
44 | except OSError: | ||
45 | os.remove(lock) | ||
46 | raise | ||
47 | |||
33 | def _error(fmt, *args): | 48 | def _error(fmt, *args): |
34 | msg = fmt % args | 49 | msg = fmt % args |
35 | print >>sys.stderr, 'error: %s' % msg | 50 | print >>sys.stderr, 'error: %s' % msg |
@@ -758,31 +773,54 @@ class Project(object): | |||
758 | def StartBranch(self, name): | 773 | def StartBranch(self, name): |
759 | """Create a new branch off the manifest's revision. | 774 | """Create a new branch off the manifest's revision. |
760 | """ | 775 | """ |
761 | try: | 776 | head = self.work_git.GetHead() |
762 | self.bare_git.rev_parse(R_HEADS + name) | 777 | if head == (R_HEADS + name): |
763 | exists = True | 778 | return True |
764 | except GitError: | ||
765 | exists = False; | ||
766 | 779 | ||
767 | if exists: | 780 | all = self.bare_ref.all |
768 | if name == self.CurrentBranch: | 781 | if (R_HEADS + name) in all: |
769 | return True | 782 | cmd = ['checkout', name, '--'] |
770 | else: | 783 | return GitCommand(self, |
771 | cmd = ['checkout', name, '--'] | 784 | cmd, |
772 | return GitCommand(self, cmd).Wait() == 0 | 785 | capture_stdout = True).Wait() == 0 |
786 | |||
787 | branch = self.GetBranch(name) | ||
788 | branch.remote = self.GetRemote(self.remote.name) | ||
789 | branch.merge = self.revision | ||
773 | 790 | ||
791 | rev = branch.LocalMerge | ||
792 | if rev in all: | ||
793 | revid = all[rev] | ||
794 | elif IsId(rev): | ||
795 | revid = rev | ||
774 | else: | 796 | else: |
775 | branch = self.GetBranch(name) | 797 | revid = None |
776 | branch.remote = self.GetRemote(self.remote.name) | 798 | |
777 | branch.merge = self.revision | 799 | if head.startswith(R_HEADS): |
778 | 800 | try: | |
779 | rev = branch.LocalMerge | 801 | head = all[head] |
780 | cmd = ['checkout', '-b', branch.name, rev] | 802 | except KeyError: |
781 | if GitCommand(self, cmd).Wait() == 0: | 803 | head = None |
782 | branch.Save() | 804 | |
783 | return True | 805 | if revid and head and revid == head: |
784 | else: | 806 | ref = os.path.join(self.gitdir, R_HEADS + name) |
785 | return False | 807 | try: |
808 | os.makedirs(os.path.dirname(ref)) | ||
809 | except OSError: | ||
810 | pass | ||
811 | _lwrite(ref, '%s\n' % revid) | ||
812 | _lwrite(os.path.join(self.worktree, '.git', HEAD), | ||
813 | 'ref: %s%s\n' % (R_HEADS, name)) | ||
814 | branch.Save() | ||
815 | return True | ||
816 | |||
817 | cmd = ['checkout', '-b', branch.name, rev] | ||
818 | if GitCommand(self, | ||
819 | cmd, | ||
820 | capture_stdout = True).Wait() == 0: | ||
821 | branch.Save() | ||
822 | return True | ||
823 | return False | ||
786 | 824 | ||
787 | def CheckoutBranch(self, name): | 825 | def CheckoutBranch(self, name): |
788 | """Checkout a local topic branch. | 826 | """Checkout a local topic branch. |