Index: gclient_scm.py |
diff --git a/gclient_scm.py b/gclient_scm.py |
index 5a5dc075b3c6c4b5ffb81b11c9702a37e1815dc2..fd7e3eed1c51fcdebefa3b64d08d7acd8f7c8ba8 100644 |
--- a/gclient_scm.py |
+++ b/gclient_scm.py |
@@ -382,6 +382,7 @@ class GitWrapper(SCMWrapper): |
# See if the url has changed (the unittests use git://foo for the url, let |
# that through). |
current_url = self._Capture(['config', 'remote.origin.url']) |
+ return_early = False |
# TODO(maruel): Delete url != 'git://foo' since it's just to make the |
# unit test pass. (and update the comment above) |
# Skip url auto-correction if remote.origin.gclient-auto-fix-url is set. |
@@ -398,6 +399,13 @@ class GitWrapper(SCMWrapper): |
# Switch over to the new upstream |
self._Run(['remote', 'set-url', 'origin', url], options) |
self._FetchAndReset(revision, file_list, options) |
+ return_early = True |
+ |
+ # Need to do this in the normal path as well as in the post-remote-switch |
+ # path. |
+ self._PossiblySwitchCache(url, options) |
+ |
+ if return_early: |
return |
if not self._IsValidGitRepo(): |
@@ -735,6 +743,44 @@ class GitWrapper(SCMWrapper): |
url += '.git' |
return url |
+ def _PossiblySwitchCache(self, url, options): |
+ """Handles switching a repo from with-cache to direct, or vice versa. |
+ |
+ When we go from direct to with-cache, the remote url changes from the |
+ 'real' url to the local file url (in cache_dir). Therefore, this function |
+ assumes that |url| points to the correctly-switched-over local file url, if |
+ we're in cache_mode. |
+ |
+ When we go from with-cache to direct, assume that the normal url-switching |
+ code already flipped the remote over, and we just need to repack and break |
+ the dependency to the cache. |
+ """ |
+ |
+ altfile = os.path.join( |
+ self.checkout_path, '.git', 'objects', 'info', 'alternates') |
+ if self.cache_dir: |
+ if not os.path.exists(altfile): |
+ try: |
+ with open(altfile, 'wa') as f: |
+ f.write(os.path.join(url, 'objects')) |
+ # pylint: disable=C0301 |
+ # This dance is necessary according to emperical evidence, also at: |
+ # http://lists-archives.com/git/713652-retrospectively-add-alternates-to-a-repository.html |
+ self._Run(['repack', '-ad'], options) |
+ self._Run(['repack', '-adl'], options) |
+ except Exception: |
+ # If something goes wrong, try to remove the altfile so we'll go down |
+ # this path again next time. |
+ try: |
+ os.remove(altfile) |
+ except Exception: |
+ pass |
+ raise |
+ else: |
+ if os.path.exists(altfile): |
+ self._Run(['repack', '-a'], options) |
+ os.remove(altfile) |
+ |
def _CreateOrUpdateCache(self, url, options): |
"""Make a new git mirror or update existing mirror for |url|, and return the |
mirror URI to clone from. |
@@ -748,6 +794,16 @@ class GitWrapper(SCMWrapper): |
folder = os.path.join( |
self.cache_dir, |
self._NormalizeGitURL(url).replace('-', '--').replace('/', '-')) |
+ altfile = os.path.join(folder, 'objects', 'info', 'alternates') |
+ |
+ # If we're bringing an old cache up to date or cloning a new cache, and the |
+ # existing repo is currently a direct clone, use its objects to help out |
+ # the fetch here. |
+ checkout_objects = os.path.join(self.checkout_path, '.git', 'objects') |
+ checkout_altfile = os.path.join(checkout_objects, 'info', 'alternates') |
+ use_reference = ( |
+ os.path.exists(checkout_objects) and |
+ not os.path.exists(checkout_altfile)) |
v = ['-v'] if options.verbose else [] |
filter_fn = lambda l: '[up to date]' not in l |
@@ -755,8 +811,13 @@ class GitWrapper(SCMWrapper): |
gclient_utils.safe_makedirs(self.cache_dir) |
if not os.path.exists(os.path.join(folder, 'config')): |
gclient_utils.rmtree(folder) |
- self._Run(['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g', |
- '--progress', '--mirror', url, folder], |
+ cmd = ['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g', |
+ '--progress', '--mirror'] |
+ |
+ if use_reference: |
+ cmd += ['--reference', os.path.abspath(self.checkout_path)] |
+ |
+ self._Run(cmd + [url, folder], |
options, git_filter=True, filter_fn=filter_fn, |
cwd=self.cache_dir) |
else: |
@@ -768,10 +829,20 @@ class GitWrapper(SCMWrapper): |
cwd=folder) |
assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) |
+ if use_reference: |
+ with open(altfile, 'w') as f: |
+ f.write(os.path.abspath(checkout_objects)) |
+ |
# Would normally use `git remote update`, but it doesn't support |
# --progress, so use fetch instead. |
self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], |
options, git_filter=True, filter_fn=filter_fn, cwd=folder) |
+ |
+ # If the clone has an object dependency on the existing repo, break it |
+ # with repack and remove the linkage. |
+ if os.path.exists(altfile): |
+ self._Run(['repack', '-a'], options, cwd=folder) |
+ os.remove(altfile) |
return folder |
def _Clone(self, revision, url, options): |