mirror of
https://gerrit.googlesource.com/git-repo
synced 2024-12-21 07:16:21 +00:00
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>
This commit is contained in:
parent
db45da1208
commit
accc56d82b
@ -57,6 +57,7 @@ class GitConfig(object):
|
||||
self.file = file
|
||||
self.defaults = defaults
|
||||
self._cache_dict = None
|
||||
self._section_dict = None
|
||||
self._remotes = {}
|
||||
self._branches = {}
|
||||
self._pickle = os.path.join(
|
||||
@ -168,6 +169,33 @@ class GitConfig(object):
|
||||
self._branches[b.name] = b
|
||||
return b
|
||||
|
||||
def HasSection(self, section, subsection = ''):
|
||||
"""Does at least one key in section.subsection exist?
|
||||
"""
|
||||
try:
|
||||
return subsection in self._sections[section]
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
@property
|
||||
def _sections(self):
|
||||
d = self._section_dict
|
||||
if d is None:
|
||||
d = {}
|
||||
for name in self._cache.keys():
|
||||
p = name.split('.')
|
||||
if 2 == len(p):
|
||||
section = p[0]
|
||||
subsect = ''
|
||||
else:
|
||||
section = p[0]
|
||||
subsect = '.'.join(p[1:-1])
|
||||
if section not in d:
|
||||
d[section] = set()
|
||||
d[section].add(subsect)
|
||||
self._section_dict = d
|
||||
return d
|
||||
|
||||
@property
|
||||
def _cache(self):
|
||||
if self._cache_dict is None:
|
||||
@ -443,11 +471,23 @@ class Branch(object):
|
||||
def Save(self):
|
||||
"""Save this branch back into the configuration.
|
||||
"""
|
||||
self._Set('merge', self.merge)
|
||||
if self.remote:
|
||||
self._Set('remote', self.remote.name)
|
||||
if self._config.HasSection('branch', self.name):
|
||||
if self.remote:
|
||||
self._Set('remote', self.remote.name)
|
||||
else:
|
||||
self._Set('remote', None)
|
||||
self._Set('merge', self.merge)
|
||||
|
||||
else:
|
||||
self._Set('remote', None)
|
||||
fd = open(self._config.file, 'ab')
|
||||
try:
|
||||
fd.write('[branch "%s"]\n' % self.name)
|
||||
if self.remote:
|
||||
fd.write('\tremote = %s\n' % self.remote.name)
|
||||
if self.merge:
|
||||
fd.write('\tmerge = %s\n' % self.merge)
|
||||
finally:
|
||||
fd.close()
|
||||
|
||||
def _Set(self, key, value):
|
||||
key = 'branch.%s.%s' % (self.name, key)
|
||||
|
80
project.py
80
project.py
@ -30,6 +30,21 @@ from remote import Remote
|
||||
|
||||
from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M
|
||||
|
||||
def _lwrite(path, content):
|
||||
lock = '%s.lock' % path
|
||||
|
||||
fd = open(lock, 'wb')
|
||||
try:
|
||||
fd.write(content)
|
||||
finally:
|
||||
fd.close()
|
||||
|
||||
try:
|
||||
os.rename(lock, path)
|
||||
except OSError:
|
||||
os.remove(lock)
|
||||
raise
|
||||
|
||||
def _error(fmt, *args):
|
||||
msg = fmt % args
|
||||
print >>sys.stderr, 'error: %s' % msg
|
||||
@ -758,31 +773,54 @@ class Project(object):
|
||||
def StartBranch(self, name):
|
||||
"""Create a new branch off the manifest's revision.
|
||||
"""
|
||||
try:
|
||||
self.bare_git.rev_parse(R_HEADS + name)
|
||||
exists = True
|
||||
except GitError:
|
||||
exists = False;
|
||||
head = self.work_git.GetHead()
|
||||
if head == (R_HEADS + name):
|
||||
return True
|
||||
|
||||
if exists:
|
||||
if name == self.CurrentBranch:
|
||||
return True
|
||||
else:
|
||||
cmd = ['checkout', name, '--']
|
||||
return GitCommand(self, cmd).Wait() == 0
|
||||
all = self.bare_ref.all
|
||||
if (R_HEADS + name) in all:
|
||||
cmd = ['checkout', name, '--']
|
||||
return GitCommand(self,
|
||||
cmd,
|
||||
capture_stdout = True).Wait() == 0
|
||||
|
||||
branch = self.GetBranch(name)
|
||||
branch.remote = self.GetRemote(self.remote.name)
|
||||
branch.merge = self.revision
|
||||
|
||||
rev = branch.LocalMerge
|
||||
if rev in all:
|
||||
revid = all[rev]
|
||||
elif IsId(rev):
|
||||
revid = rev
|
||||
else:
|
||||
branch = self.GetBranch(name)
|
||||
branch.remote = self.GetRemote(self.remote.name)
|
||||
branch.merge = self.revision
|
||||
revid = None
|
||||
|
||||
rev = branch.LocalMerge
|
||||
cmd = ['checkout', '-b', branch.name, rev]
|
||||
if GitCommand(self, cmd).Wait() == 0:
|
||||
branch.Save()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
if head.startswith(R_HEADS):
|
||||
try:
|
||||
head = all[head]
|
||||
except KeyError:
|
||||
head = None
|
||||
|
||||
if revid and head and revid == head:
|
||||
ref = os.path.join(self.gitdir, R_HEADS + name)
|
||||
try:
|
||||
os.makedirs(os.path.dirname(ref))
|
||||
except OSError:
|
||||
pass
|
||||
_lwrite(ref, '%s\n' % revid)
|
||||
_lwrite(os.path.join(self.worktree, '.git', HEAD),
|
||||
'ref: %s%s\n' % (R_HEADS, name))
|
||||
branch.Save()
|
||||
return True
|
||||
|
||||
cmd = ['checkout', '-b', branch.name, rev]
|
||||
if GitCommand(self,
|
||||
cmd,
|
||||
capture_stdout = True).Wait() == 0:
|
||||
branch.Save()
|
||||
return True
|
||||
return False
|
||||
|
||||
def CheckoutBranch(self, name):
|
||||
"""Checkout a local topic branch.
|
||||
|
Loading…
Reference in New Issue
Block a user