From accc56d82b902e7c7a22401db710958fcb1c7b58 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 18 Apr 2009 14:45:51 -0700 Subject: 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 --- project.py | 82 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 22 deletions(-) (limited to 'project.py') 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 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 - - rev = branch.LocalMerge - cmd = ['checkout', '-b', branch.name, rev] - if GitCommand(self, cmd).Wait() == 0: - branch.Save() - return True - else: - return False + revid = None + + 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. -- cgit v1.2.3-54-g00ecf