summaryrefslogtreecommitdiffstats
path: root/subcmds
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2020-02-09 02:28:34 -0500
committerMike Frysinger <vapier@google.com>2020-02-19 18:11:33 +0000
commit979d5bdc3ebe45998a76dbbaff46c33d4e59683b (patch)
tree97c639570a60dd02a6ee9b712dff091a83ac8110 /subcmds
parent56ce3468b4f2faa1cccfea01dc91e7db73fb3843 (diff)
downloadgit-repo-979d5bdc3ebe45998a76dbbaff46c33d4e59683b.tar.gz
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 <vapier@google.com> Reviewed-by: Mike Frysinger <vapier@google.com>
Diffstat (limited to 'subcmds')
-rw-r--r--subcmds/init.py24
-rw-r--r--subcmds/sync.py24
2 files changed, 42 insertions, 6 deletions
diff --git a/subcmds/init.py b/subcmds/init.py
index 3c68c2c3..8a29321e 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -15,6 +15,8 @@
15# limitations under the License. 15# limitations under the License.
16 16
17from __future__ import print_function 17from __future__ import print_function
18
19import optparse
18import os 20import os
19import platform 21import platform
20import re 22import re
@@ -128,6 +130,10 @@ to update the working directory files.
128 g.add_option('--clone-filter', action='store', default='blob:none', 130 g.add_option('--clone-filter', action='store', default='blob:none',
129 dest='clone_filter', 131 dest='clone_filter',
130 help='filter for use with --partial-clone [default: %default]') 132 help='filter for use with --partial-clone [default: %default]')
133 # TODO(vapier): Expose option with real help text once this has been in the
134 # wild for a while w/out significant bug reports. Goal is by ~Sep 2020.
135 g.add_option('--worktree', action='store_true',
136 help=optparse.SUPPRESS_HELP)
131 g.add_option('--archive', 137 g.add_option('--archive',
132 dest='archive', action='store_true', 138 dest='archive', action='store_true',
133 help='checkout an archive instead of a git repository for ' 139 help='checkout an archive instead of a git repository for '
@@ -246,6 +252,20 @@ to update the working directory files.
246 if opt.dissociate: 252 if opt.dissociate:
247 m.config.SetString('repo.dissociate', 'true') 253 m.config.SetString('repo.dissociate', 'true')
248 254
255 if opt.worktree:
256 if opt.mirror:
257 print('fatal: --mirror and --worktree are incompatible',
258 file=sys.stderr)
259 sys.exit(1)
260 if opt.submodules:
261 print('fatal: --submodules and --worktree are incompatible',
262 file=sys.stderr)
263 sys.exit(1)
264 m.config.SetString('repo.worktree', 'true')
265 if is_new:
266 m.use_git_worktrees = True
267 print('warning: --worktree is experimental!', file=sys.stderr)
268
249 if opt.archive: 269 if opt.archive:
250 if is_new: 270 if is_new:
251 m.config.SetString('repo.archive', 'true') 271 m.config.SetString('repo.archive', 'true')
@@ -459,6 +479,10 @@ to update the working directory files.
459 % ('.'.join(str(x) for x in MIN_GIT_VERSION_SOFT),), 479 % ('.'.join(str(x) for x in MIN_GIT_VERSION_SOFT),),
460 file=sys.stderr) 480 file=sys.stderr)
461 481
482 if opt.worktree:
483 # Older versions of git supported worktree, but had dangerous gc bugs.
484 git_require((2, 15, 0), fail=True, msg='git gc worktree corruption')
485
462 self._SyncManifest(opt) 486 self._SyncManifest(opt)
463 self._LinkManifest(opt.manifest_name) 487 self._LinkManifest(opt.manifest_name)
464 488
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 @@
15# limitations under the License. 15# limitations under the License.
16 16
17from __future__ import print_function 17from __future__ import print_function
18
19import errno
18import json 20import json
19import netrc 21import netrc
20from optparse import SUPPRESS_HELP 22from optparse import SUPPRESS_HELP
@@ -569,7 +571,8 @@ later is required to fix a server side protocol bug.
569 gc_gitdirs = {} 571 gc_gitdirs = {}
570 for project in projects: 572 for project in projects:
571 # Make sure pruning never kicks in with shared projects. 573 # Make sure pruning never kicks in with shared projects.
572 if len(project.manifest.GetProjectsWithName(project.name)) > 1: 574 if (not project.use_git_worktrees and
575 len(project.manifest.GetProjectsWithName(project.name)) > 1):
573 print('%s: Shared project %s found, disabling pruning.' % 576 print('%s: Shared project %s found, disabling pruning.' %
574 (project.relpath, project.name)) 577 (project.relpath, project.name))
575 if git_require((2, 7, 0)): 578 if git_require((2, 7, 0)):
@@ -637,13 +640,22 @@ later is required to fix a server side protocol bug.
637 # Delete the .git directory first, so we're less likely to have a partially 640 # Delete the .git directory first, so we're less likely to have a partially
638 # working git repository around. There shouldn't be any git projects here, 641 # working git repository around. There shouldn't be any git projects here,
639 # so rmtree works. 642 # so rmtree works.
643 dotgit = os.path.join(path, '.git')
644 # Try to remove plain files first in case of git worktrees. If this fails
645 # for any reason, we'll fall back to rmtree, and that'll display errors if
646 # it can't remove things either.
647 try:
648 platform_utils.remove(dotgit)
649 except OSError:
650 pass
640 try: 651 try:
641 platform_utils.rmtree(os.path.join(path, '.git')) 652 platform_utils.rmtree(dotgit)
642 except OSError as e: 653 except OSError as e:
643 print('Failed to remove %s (%s)' % (os.path.join(path, '.git'), str(e)), file=sys.stderr) 654 if e.errno != errno.ENOENT:
644 print('error: Failed to delete obsolete path %s' % path, file=sys.stderr) 655 print('error: %s: %s' % (dotgit, str(e)), file=sys.stderr)
645 print(' remove manually, then run sync again', file=sys.stderr) 656 print('error: %s: Failed to delete obsolete path; remove manually, then '
646 return 1 657 'run sync again' % (path,), file=sys.stderr)
658 return 1
647 659
648 # Delete everything under the worktree, except for directories that contain 660 # Delete everything under the worktree, except for directories that contain
649 # another git project 661 # another git project