private static Commit LookUpCommit(IRepository repository, string committish)
        {
            GitObject obj = repository.Lookup(committish);

            Ensure.GitObjectIsNotNull(obj, committish);
            return(obj.Peel <Commit>(true));
        }
Example #2
0
        /// <summary>
        /// Checkout the specified <see cref="Branch"/>, reference or SHA.
        /// <para>
        ///   If the committishOrBranchSpec parameter resolves to a branch name, then the checked out HEAD will
        ///   will point to the branch. Otherwise, the HEAD will be detached, pointing at the commit sha.
        /// </para>
        /// </summary>
        /// <param name="repository">The repository to act on</param>
        /// <param name="committishOrBranchSpec">A revparse spec for the commit or branch to checkout.</param>
        /// <param name="options"><see cref="CheckoutOptions"/> controlling checkout behavior.</param>
        /// <returns>The <see cref="Branch"/> that was checked out.</returns>
        public static Branch Checkout(IRepository repository, string committishOrBranchSpec, CheckoutOptions options)
        {
            Ensure.ArgumentNotNull(repository, "repository");
            Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec");
            Ensure.ArgumentNotNull(options, "options");

            Reference reference = null;
            GitObject obj       = null;
            Branch    branch    = null;

            try
            {
                repository.RevParse(committishOrBranchSpec, out reference, out obj);
            }
            catch (NotFoundException)
            {
                // If committishOrBranchSpec is not a local branch but matches a tracking branch
                // in exactly one remote, use it. This is the "git checkout" command's default behavior.
                // https://git-scm.com/docs/git-checkout#Documentation/git-checkout.txt-emgitcheckoutemltbranchgt
                var remoteBranches = repository.Network.Remotes
                                     .SelectMany(r => repository.Branches.Where(b =>
                                                                                b.IsRemote &&
                                                                                b.CanonicalName == $"refs/remotes/{r.Name}/{committishOrBranchSpec}"))
                                     .ToList();

                if (remoteBranches.Count == 1)
                {
                    branch = repository.CreateBranch(committishOrBranchSpec, remoteBranches[0].Tip);
                    repository.Branches.Update(branch, b => b.TrackedBranch = remoteBranches[0].CanonicalName);

                    return(Checkout(repository, branch, options));
                }

                if (remoteBranches.Count > 1)
                {
                    throw new AmbiguousSpecificationException($"'{committishOrBranchSpec}' matched multiple ({remoteBranches.Count}) remote tracking branches");
                }

                throw;
            }

            if (reference != null && reference.IsLocalBranch)
            {
                branch = repository.Branches[reference.CanonicalName];
                return(Checkout(repository, branch, options));
            }

            Commit commit = obj.Peel <Commit>(true);

            Checkout(repository, commit.Tree, options, committishOrBranchSpec);

            return(repository.Head);
        }