From 979d5bdc3ebe45998a76dbbaff46c33d4e59683b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 9 Feb 2020 02:28:34 -0500 Subject: add experimental git worktree support This provides initial support for using git worktrees internally instead of our own ad-hoc symlink tree. It's been lightly tested which is why it's not currently exposed via --help. When people opt-in to worktrees in an existing repo client checkout, no projects are migrated. Instead, only new projects will use the worktree method. This allows for limited testing/opting in without having to completely blow things away or get a second checkout. Bug: https://crbug.com/gerrit/11486 Change-Id: Ic3ff891b30940a6ba497b406b2a387e0a8517ed8 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/254075 Tested-by: Mike Frysinger Reviewed-by: Mike Frysinger --- subcmds/sync.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'subcmds/sync.py') diff --git a/subcmds/sync.py b/subcmds/sync.py index 0ac308e6..49867a97 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py @@ -15,6 +15,8 @@ # limitations under the License. from __future__ import print_function + +import errno import json import netrc from optparse import SUPPRESS_HELP @@ -569,7 +571,8 @@ later is required to fix a server side protocol bug. gc_gitdirs = {} for project in projects: # Make sure pruning never kicks in with shared projects. - if len(project.manifest.GetProjectsWithName(project.name)) > 1: + if (not project.use_git_worktrees and + len(project.manifest.GetProjectsWithName(project.name)) > 1): print('%s: Shared project %s found, disabling pruning.' % (project.relpath, project.name)) if git_require((2, 7, 0)): @@ -637,13 +640,22 @@ later is required to fix a server side protocol bug. # Delete the .git directory first, so we're less likely to have a partially # working git repository around. There shouldn't be any git projects here, # so rmtree works. + dotgit = os.path.join(path, '.git') + # Try to remove plain files first in case of git worktrees. If this fails + # for any reason, we'll fall back to rmtree, and that'll display errors if + # it can't remove things either. + try: + platform_utils.remove(dotgit) + except OSError: + pass try: - platform_utils.rmtree(os.path.join(path, '.git')) + platform_utils.rmtree(dotgit) except OSError as e: - print('Failed to remove %s (%s)' % (os.path.join(path, '.git'), str(e)), file=sys.stderr) - print('error: Failed to delete obsolete path %s' % path, file=sys.stderr) - print(' remove manually, then run sync again', file=sys.stderr) - return 1 + if e.errno != errno.ENOENT: + print('error: %s: %s' % (dotgit, str(e)), file=sys.stderr) + print('error: %s: Failed to delete obsolete path; remove manually, then ' + 'run sync again' % (path,), file=sys.stderr) + return 1 # Delete everything under the worktree, except for directories that contain # another git project -- cgit v1.2.3-54-g00ecf