using libgit2sharp to pull latest from a branch

2019-07-21 01:14发布

问题:

I am using libgit2sharp in a c# solution to switch to a branch and pull in the latest changes. Here is the code I am using:

    public void FetchAll()
    {
        using (var repo = new Repository(_LocalGitPath))
        {
            foreach (Remote remote in repo.Network.Remotes)
            {
                FetchOptions options = new FetchOptions();
                options.CredentialsProvider = new CredentialsHandler((url, usernameFromUrl, types) => new UsernamePasswordCredentials()
                {
                    Username = _UserName,
                    Password = _Password
                });
                repo.Network.Fetch(remote, options);
            }
        }
    }
    public string CheckoutBranch(string branchName)
    {
        using (var repo = new Repository(_LocalGitPath))
        {
            var trackingBranch = repo.Branches[branchName];

            if (trackingBranch.IsRemote)
            {
                branchName = branchName.Replace("origin/", string.Empty);

                var branch = repo.CreateBranch(branchName, trackingBranch.Tip);
                repo.Branches.Update(branch, b => b.TrackedBranch = trackingBranch.CanonicalName);
                Commands.Checkout(repo, branch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
            }
            else
            {
                Commands.Checkout(repo, trackingBranch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
            }

            return branchName;
        }
    }
    public void PullBranch(string branchName)
    {
        using (var repo = new Repository(_LocalGitPath))
        {
            PullOptions options = new PullOptions();

            options.MergeOptions = new MergeOptions();
            options.MergeOptions.FailOnConflict = true;

            options.FetchOptions = new FetchOptions();
            options.FetchOptions.CredentialsProvider = new CredentialsHandler((url, usernameFromUrl, types) => new UsernamePasswordCredentials()
            {
                Username = _UserName,
                Password = _Password
            });

            repo.Network.Pull(new Signature(_UserName, _Password, new DateTimeOffset(DateTime.Now)), options);
        }
    }

I have no problem fetching, and checking out a branch. When I try to pull latest, I get an error saying, 'There is no tracking information for the current branch.' I believe that this means that the local branch doesn't know what the correct remote repository is to pull changes from, but I haven't been able to figure out how to tell libgit2sharp what the remote repo path is. Anyone have any suggestions?

While doing research on this problem I found this: https://github.com/libgit2/libgit2sharp/issues/1235. Essentially, a libgit2sharp dev describes the exact problem I am seeing, but doesn't provide any code for the fix.

One additional note: I will never be merging or pushing any changes back from this repository. I am pulling it for an automated build, so we can ignore or overwrite any local changes. I just need to get the latest code.

SOLUTION: I have updated the code above with the solution that I got working. You need to be really careful to make sure that when you checkout a branch, you check the isRemote flag on the branch you are checking out is set to true. If you checkout a branch that isn't a remote it will set the remote to '.' in your git config file, and you need to manually fix it. If there isn't a valid remote you will not be able to pull the branch changes.

Do not use the code sample on the libgit2sharp wiki unless they add this check in.

回答1:

You can setup the tracking brach information on the local branch by using the Refspec:

using (var repo = new Repository("/Users/sushi/code/redux/mono"))
{
    var trackingBranch = repo.Branches["remotes/origin/work-btls"];
    if (trackingBranch.IsRemote)
    {
        var branch = repo.CreateBranch("SomeLocalBranchName", trackingBranch.Tip);
        repo.Branches.Update(branch, b => b.TrackedBranch = trackingBranch.CanonicalName);
        repo.Checkout(branch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
    }
}

You can use git to verify that SomeLocalBranchName is now tracking remotes/origin/work-btls:

>>>git for-each-ref --format='%(refname:short) <- %(upstream:short)' refs/heads

SomeLocalBranchName <- remotes/origin/work-btls
master <- origin/master 

>>>git status

On branch SomeLocalBranchName
Your branch is up-to-date with 'remotes/origin/work-btls'.