project: store objects in project-objects directly

In order to stop sharing objects/ directly between shared projects,
we have to fetch the remote objects into project-objects/ manually.
So instead of running git operations in the individual project dirs
and relying on .git/objects being symlinked to project-objects/,
tell git to store any objects it fetches in project-objects/.

We do this by leveraging the GIT_OBJECT_DIRECTORY override.  This
has been in git forever, or at least since v1.7.2 which is what we
already hard require.  This tells git to save new objects to the
specified path no matter where it's being run otherwise.

We still otherwise run git in the project-specific dir so that it
can find the right set of refs that it wants to compare against,
including local refs.  For that reason, we also have to leverage
GIT_ALTERNATE_OBJECT_DIRECTORIES to tell git where to find objects
that are not in the upstream remote.  This way git doesn't blow up
when it can't find objects only associated with local commits.

As it stands right now, the practical result is the same: since we
symlink the project objects/ dir to the project-objects/ tree, the
default objects dir, the one we set $GIT_OBJECT_DIRECTORY to, and
the one we set $GIT_ALTERNATE_OBJECT_DIRECTORIES to are actually
all the same.  So this commit by itself should be safe.  But in a
follow up commit, we can replace the symlink with a separate dir
and git will keep working.

Bug: https://crbug.com/gerrit/15553
Change-Id: Ie4e654aec3e1ee307eee925a54908a2db6a5869f
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/328100
Reviewed-by: Jack Neus <jackneus@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
This commit is contained in:
Mike Frysinger 2021-12-23 17:36:09 -05:00
parent 152032cca2
commit 67d6cdf2bc
2 changed files with 27 additions and 7 deletions

View File

@ -169,7 +169,8 @@ class GitCommand(object):
disable_editor=False, disable_editor=False,
ssh_proxy=None, ssh_proxy=None,
cwd=None, cwd=None,
gitdir=None): gitdir=None,
objdir=None):
env = self._GetBasicEnv() env = self._GetBasicEnv()
if disable_editor: if disable_editor:
@ -194,13 +195,24 @@ class GitCommand(object):
cwd = project.worktree cwd = project.worktree
if not gitdir: if not gitdir:
gitdir = project.gitdir gitdir = project.gitdir
# Git on Windows wants its paths only using / for reliability.
if platform_utils.isWindows():
if objdir:
objdir = objdir.replace('\\', '/')
if gitdir:
gitdir = gitdir.replace('\\', '/')
if objdir:
# Set to the place we want to save the objects.
env['GIT_OBJECT_DIRECTORY'] = objdir
if gitdir:
# Allow git to search the original place in case of local or unique refs
# that git will attempt to resolve even if we aren't fetching them.
env['GIT_ALTERNATE_OBJECT_DIRECTORIES'] = gitdir + '/objects'
command = [GIT] command = [GIT]
if bare: if bare:
if gitdir: if gitdir:
# Git on Windows wants its paths only using / for reliability.
if platform_utils.isWindows():
gitdir = gitdir.replace('\\', '/')
env[GIT_DIR] = gitdir env[GIT_DIR] = gitdir
cwd = None cwd = None
command.append(cmdv[0]) command.append(cmdv[0])
@ -234,6 +246,11 @@ class GitCommand(object):
dbg += ': export GIT_DIR=%s\n' % env[GIT_DIR] dbg += ': export GIT_DIR=%s\n' % env[GIT_DIR]
LAST_GITDIR = env[GIT_DIR] LAST_GITDIR = env[GIT_DIR]
if 'GIT_OBJECT_DIRECTORY' in env:
dbg += ': export GIT_OBJECT_DIRECTORY=%s\n' % env['GIT_OBJECT_DIRECTORY']
if 'GIT_ALTERNATE_OBJECT_DIRECTORIES' in env:
dbg += ': export GIT_ALTERNATE_OBJECT_DIRECTORIES=%s\n' % env['GIT_ALTERNATE_OBJECT_DIRECTORIES']
dbg += ': ' dbg += ': '
dbg += ' '.join(command) dbg += ' '.join(command)
if stdin == subprocess.PIPE: if stdin == subprocess.PIPE:

View File

@ -2192,8 +2192,10 @@ class Project(object):
retry_cur_sleep = retry_sleep_initial_sec retry_cur_sleep = retry_sleep_initial_sec
ok = prune_tried = False ok = prune_tried = False
for try_n in range(retry_fetches): for try_n in range(retry_fetches):
gitcmd = GitCommand(self, cmd, bare=True, ssh_proxy=ssh_proxy, gitcmd = GitCommand(
merge_output=True, capture_stdout=quiet or bool(output_redir)) self, cmd, bare=True, objdir=os.path.join(self.objdir, 'objects'),
ssh_proxy=ssh_proxy,
merge_output=True, capture_stdout=quiet or bool(output_redir))
if gitcmd.stdout and not quiet and output_redir: if gitcmd.stdout and not quiet and output_redir:
output_redir.write(gitcmd.stdout) output_redir.write(gitcmd.stdout)
ret = gitcmd.Wait() ret = gitcmd.Wait()
@ -2309,7 +2311,8 @@ class Project(object):
cmd.append(str(f)) cmd.append(str(f))
cmd.append('+refs/tags/*:refs/tags/*') cmd.append('+refs/tags/*:refs/tags/*')
ok = GitCommand(self, cmd, bare=True).Wait() == 0 ok = GitCommand(
self, cmd, bare=True, objdir=os.path.join(self.objdir, 'objects')).Wait() == 0
platform_utils.remove(bundle_dst, missing_ok=True) platform_utils.remove(bundle_dst, missing_ok=True)
platform_utils.remove(bundle_tmp, missing_ok=True) platform_utils.remove(bundle_tmp, missing_ok=True)
return ok return ok