sync: change how we preserve objects in shared repos

Some automatic git operations will prune objects on us, and not just
the gc step.  Normally we don't care, but with shared projects, we
will have multiple git checkouts with refs that the others cannot
see, but with a shared object dir.  Any pruning of objects based on
refs in just one repo can easily break the others.

git-2.7.0 introduced a preciousObjects setting which tells git to
never prune objects for this exact scenario: there might be refs in
some location that git is unable to see.

Change-Id: I781de27c5bbe1d4c70f0187566141c9cce088bd8
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/254392
Reviewed-by: Nasser Grainawi <nasser@codeaurora.org>
Reviewed-by: David Riley <davidriley@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 808df20..f41de8d 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -560,9 +560,20 @@
   def _GCProjects(self, projects, opt, err_event):
     gc_gitdirs = {}
     for project in projects:
+      # Make sure pruning never kicks in with shared projects.
       if len(project.manifest.GetProjectsWithName(project.name)) > 1:
-        print('Shared project %s found, disabling pruning.' % project.name)
-        project.bare_git.config('--replace-all', 'gc.pruneExpire', 'never')
+        print('%s: Shared project %s found, disabling pruning.' %
+              (project.relpath, project.name))
+        if git_require((2, 7, 0)):
+          project.config.SetString('core.repositoryFormatVersion', '1')
+          project.config.SetString('extensions.preciousObjects', 'true')
+        else:
+          # This isn't perfect, but it's the best we can do with old git.
+          print('%s: WARNING: shared projects are unreliable when using old '
+                'versions of git; please upgrade to git-2.7.0+.'
+                % (project.relpath,),
+                file=sys.stderr)
+          project.config.SetString('gc.pruneExpire', 'never')
       gc_gitdirs[project.gitdir] = project.bare_git
 
     has_dash_c = git_require((1, 7, 2))