Skip to content

Commit c06020d

Browse files
committed
Skip commit pack download during clone when prefetch packs exist
When gvfs clone runs with a shared cache that already has prefetch packs (e.g., from a previous clone), defer the commit+trees pack download. If the commit is already present in the prefetch packs, the download is skipped entirely. If it is not, the fallback path downloads on demand when branch creation, gitattributes lookup, or checkout requires it. This avoids redundantly re-downloading trees that are already in prefetch packs when the tip commit happens to be covered by the existing cache. Assisted-by: Claude Opus 4.6 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
1 parent b65af3a commit c06020d

1 file changed

Lines changed: 90 additions & 10 deletions

File tree

GVFS/GVFS/CommandLine/CloneVerb.cs

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,29 @@ private static bool IsForceCheckoutErrorCloneFailure(string checkoutError)
361361
return true;
362362
}
363363

364+
private static bool HasUsablePrefetchPacks(
365+
GVFSGitObjects gitObjects,
366+
GVFSEnlistment enlistment,
367+
PhysicalFileSystem fileSystem)
368+
{
369+
string[] prefetchPacks = gitObjects.ReadPackFileNames(
370+
enlistment.GitPackRoot,
371+
GVFSConstants.PrefetchPackPrefix);
372+
373+
foreach (string packPath in prefetchPacks)
374+
{
375+
string idxPath = Path.ChangeExtension(packPath, ".idx");
376+
string incompletePath = Path.ChangeExtension(packPath, GVFSConstants.InProgressPrefetchMarkerExtension);
377+
378+
if (fileSystem.FileExists(idxPath) && !fileSystem.FileExists(incompletePath))
379+
{
380+
return true;
381+
}
382+
}
383+
384+
return false;
385+
}
386+
364387
private Result TryCreateEnlistment(
365388
string fullEnlistmentRootPathParameter,
366389
string normalizedEnlistementRootPath,
@@ -617,15 +640,30 @@ private Result CreateClone(
617640
GVFSContext context = new GVFSContext(tracer, fileSystem, gitRepo, enlistment);
618641
GVFSGitObjects gitObjects = new GVFSGitObjects(context, objectRequestor);
619642

620-
if (!this.TryDownloadCommit(
621-
refs.GetTipCommitId(branch),
622-
enlistment,
623-
objectRequestor,
624-
gitObjects,
625-
gitRepo,
626-
out errorMessage))
643+
string commitId = refs.GetTipCommitId(branch);
644+
bool skippedCommitDownload = false;
645+
646+
if (gitRepo.CommitAndRootTreeExists(commitId, out _))
627647
{
628-
return new Result(errorMessage);
648+
tracer.RelatedInfo("Commit {0} already exists locally, skipping download", commitId);
649+
}
650+
else if (HasUsablePrefetchPacks(gitObjects, enlistment, fileSystem))
651+
{
652+
tracer.RelatedInfo("Prefetch packs found in shared cache but commit {0} is not present; deferring download", commitId);
653+
skippedCommitDownload = true;
654+
}
655+
else
656+
{
657+
if (!this.TryDownloadCommit(
658+
commitId,
659+
enlistment,
660+
objectRequestor,
661+
gitObjects,
662+
gitRepo,
663+
out errorMessage))
664+
{
665+
return new Result(errorMessage);
666+
}
629667
}
630668

631669
if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment) ||
@@ -643,6 +681,24 @@ private Result CreateClone(
643681
GitProcess git = new GitProcess(enlistment);
644682
string originBranchName = "origin/" + branch;
645683
GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName);
684+
if (createBranchResult.ExitCodeIsFailure && skippedCommitDownload)
685+
{
686+
tracer.RelatedInfo("Branch creation failed after deferring commit download, downloading commit now");
687+
if (!this.TryDownloadCommit(
688+
commitId,
689+
enlistment,
690+
objectRequestor,
691+
gitObjects,
692+
gitRepo,
693+
out errorMessage))
694+
{
695+
return new Result(errorMessage);
696+
}
697+
698+
skippedCommitDownload = false;
699+
createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName);
700+
}
701+
646702
if (createBranchResult.ExitCodeIsFailure)
647703
{
648704
return new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output);
@@ -654,7 +710,31 @@ private Result CreateClone(
654710

655711
if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage))
656712
{
657-
return new Result(errorMessage);
713+
if (skippedCommitDownload)
714+
{
715+
tracer.RelatedInfo("Root .gitattributes download failed after deferring commit download, downloading commit now");
716+
if (!this.TryDownloadCommit(
717+
commitId,
718+
enlistment,
719+
objectRequestor,
720+
gitObjects,
721+
gitRepo,
722+
out errorMessage))
723+
{
724+
return new Result(errorMessage);
725+
}
726+
727+
skippedCommitDownload = false;
728+
729+
if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage))
730+
{
731+
return new Result(errorMessage);
732+
}
733+
}
734+
else
735+
{
736+
return new Result(errorMessage);
737+
}
658738
}
659739

660740
this.CreateGitScript(enlistment);
@@ -677,7 +757,7 @@ private Result CreateClone(
677757
// again and retry the checkout.
678758

679759
if (!this.TryDownloadCommit(
680-
refs.GetTipCommitId(branch),
760+
commitId,
681761
enlistment,
682762
objectRequestor,
683763
gitObjects,

0 commit comments

Comments
 (0)