in GVFS/GVFS/CommandLine/CloneVerb.cs [525:681]
private Result CreateClone(
ITracer tracer,
GVFSEnlistment enlistment,
GitObjectsHttpRequestor objectRequestor,
GitRefs refs,
string branch)
{
Result initRepoResult = this.TryInitRepo(tracer, refs, enlistment);
if (!initRepoResult.Success)
{
return initRepoResult;
}
PhysicalFileSystem fileSystem = new PhysicalFileSystem();
string errorMessage;
if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out errorMessage))
{
return new Result("Error configuring alternate: " + errorMessage);
}
GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem);
GVFSContext context = new GVFSContext(tracer, fileSystem, gitRepo, enlistment);
GVFSGitObjects gitObjects = new GVFSGitObjects(context, objectRequestor);
if (!this.TryDownloadCommit(
refs.GetTipCommitId(branch),
enlistment,
objectRequestor,
gitObjects,
gitRepo,
out errorMessage))
{
return new Result(errorMessage);
}
if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment) ||
!GVFSVerb.TrySetOptionalGitConfigSettings(enlistment))
{
return new Result("Unable to configure git repo");
}
CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
if (!cacheServerResolver.TrySaveUrlToLocalConfig(objectRequestor.CacheServer, out errorMessage))
{
return new Result("Unable to configure cache server: " + errorMessage);
}
GitProcess git = new GitProcess(enlistment);
string originBranchName = "origin/" + branch;
GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName);
if (createBranchResult.ExitCodeIsFailure)
{
return new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output);
}
File.WriteAllText(
Path.Combine(enlistment.WorkingDirectoryBackingRoot, GVFSConstants.DotGit.Head),
"ref: refs/heads/" + branch);
if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage))
{
return new Result(errorMessage);
}
this.CreateGitScript(enlistment);
string installHooksError;
if (!HooksInstaller.InstallHooks(context, out installHooksError))
{
tracer.RelatedError(installHooksError);
return new Result(installHooksError);
}
GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch);
if (forceCheckoutResult.ExitCodeIsFailure && forceCheckoutResult.Errors.IndexOf("unable to read tree") > 0)
{
// It is possible to have the above TryDownloadCommit() fail because we
// already have the commit and root tree we intend to check out, but
// don't have a tree further down the working directory. If we fail
// checkout here, its' because we don't have these trees and the
// read-object hook is not available yet. Force downloading the commit
// again and retry the checkout.
if (!this.TryDownloadCommit(
refs.GetTipCommitId(branch),
enlistment,
objectRequestor,
gitObjects,
gitRepo,
out errorMessage,
checkLocalObjectCache: false))
{
return new Result(errorMessage);
}
forceCheckoutResult = git.ForceCheckout(branch);
}
if (forceCheckoutResult.ExitCodeIsFailure)
{
string[] errorLines = forceCheckoutResult.Errors.Split('\n');
StringBuilder checkoutErrors = new StringBuilder();
foreach (string gitError in errorLines)
{
if (IsForceCheckoutErrorCloneFailure(gitError))
{
checkoutErrors.AppendLine(gitError);
}
}
if (checkoutErrors.Length > 0)
{
string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString();
tracer.RelatedError(error);
return new Result(error);
}
}
if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out errorMessage))
{
tracer.RelatedError(errorMessage);
return new Result(errorMessage);
}
try
{
RepoMetadata.Instance.SaveCloneMetadata(tracer, enlistment);
this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment);
}
catch (Exception e)
{
tracer.RelatedError(e.ToString());
return new Result(e.Message);
}
finally
{
RepoMetadata.Shutdown();
}
// Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed
Exception exception;
string prepFileSystemError;
if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryBackingRoot, out prepFileSystemError, out exception))
{
EventMetadata metadata = new EventMetadata();
metadata.Add(nameof(prepFileSystemError), prepFileSystemError);
if (exception != null)
{
metadata.Add("Exception", exception.ToString());
}
tracer.RelatedError(metadata, $"{nameof(this.CreateClone)}: TryPrepareFolderForCallbacks failed");
return new Result(prepFileSystemError);
}
return new Result(true);
}