summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2009-04-18 14:45:51 -0700
committerShawn O. Pearce <sop@google.com>2009-04-18 14:45:51 -0700
commitaccc56d82b902e7c7a22401db710958fcb1c7b58 (patch)
tree3c3d233fe188315df9d87ddc247672a92167a3f5
parentdb45da12089bf131579d100ff7990cbc18d07325 (diff)
downloadgit-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.py48
-rw-r--r--project.py82
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)
diff --git a/project.py b/project.py
index 79ade3b6..8d6e4b6c 100644
--- a/project.py
+++ b/project.py
@@ -30,6 +30,21 @@ from remote import Remote
30 30
31from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M 31from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M
32 32
33def _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
33def _error(fmt, *args): 48def _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.