Improve repo sync performance by avoid git forks
By resolving the current HEAD and the manifest revision using pure
Python, we can in the common case of "no changes" avoid a lot of
git operations and directly jump out of the local sync method.
This reduces the no-op `repo sync -l` time for Android's 114 projects
from more than 6s to under 0.8s.
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/project.py b/project.py
index 086f0d7..9f9cf7b 100644
--- a/project.py
+++ b/project.py
@@ -416,22 +416,31 @@
## Publish / Upload ##
- def WasPublished(self, branch):
+ def WasPublished(self, branch, all=None):
"""Was the branch published (uploaded) for code review?
If so, returns the SHA-1 hash of the last published
state for the branch.
"""
- try:
- return self.bare_git.rev_parse(R_PUB + branch)
- except GitError:
- return None
+ key = R_PUB + branch
+ if all is None:
+ try:
+ return self.bare_git.rev_parse(key)
+ except GitError:
+ return None
+ else:
+ try:
+ return all[key]
+ except KeyError:
+ return None
- def CleanPublishedCache(self):
+ def CleanPublishedCache(self, all=None):
"""Prunes any stale published refs.
"""
+ if all is None:
+ all = self._allrefs
heads = set()
canrm = {}
- for name, id in self._allrefs.iteritems():
+ for name, id in all.iteritems():
if name.startswith(R_HEADS):
heads.add(name)
elif name.startswith(R_PUB):
@@ -567,17 +576,31 @@
Network access is not required.
"""
self._InitWorkTree()
- self.CleanPublishedCache()
+ all = self.bare_ref.all
+ self.CleanPublishedCache(all)
rem = self.GetRemote(self.remote.name)
rev = rem.ToLocal(self.revision)
- try:
- self.bare_git.rev_parse('--verify', '%s^0' % rev)
- except GitError:
- raise ManifestInvalidRevisionError(
- 'revision %s in %s not found' % (self.revision, self.name))
+ if rev in all:
+ revid = all[rev]
+ elif IsId(rev):
+ revid = rev
+ else:
+ try:
+ revid = self.bare_git.rev_parse('--verify', '%s^0' % rev)
+ except GitError:
+ raise ManifestInvalidRevisionError(
+ 'revision %s in %s not found' % (self.revision, self.name))
- branch = self.CurrentBranch
+ head = self.work_git.GetHead()
+ if head.startswith(R_HEADS):
+ branch = head[len(R_HEADS):]
+ try:
+ head = all[head]
+ except KeyError:
+ head = None
+ else:
+ branch = None
if branch is None or syncbuf.detach_head:
# Currently on a detached HEAD. The user is assumed to
@@ -588,6 +611,11 @@
syncbuf.fail(self, _PriorSyncFailedError())
return
+ if head == revid:
+ # No changes; don't do anything further.
+ #
+ return
+
lost = self._revlist(not_rev(rev), HEAD)
if lost:
syncbuf.info(self, "discarding %d commits", len(lost))
@@ -599,6 +627,11 @@
self._CopyFiles()
return
+ if head == revid:
+ # No changes; don't do anything further.
+ #
+ return
+
branch = self.GetBranch(branch)
merge = branch.LocalMerge
@@ -618,7 +651,7 @@
return
upstream_gain = self._revlist(not_rev(HEAD), rev)
- pub = self.WasPublished(branch.name)
+ pub = self.WasPublished(branch.name, all)
if pub:
not_merged = self._revlist(not_rev(rev), pub)
if not_merged:
@@ -1142,6 +1175,7 @@
if not old:
old = self.rev_parse(name)
self.update_ref('-d', name, old)
+ self._project.bare_ref.deleted(name)
def rev_list(self, *args):
cmdv = ['rev-list']