Fetch all git tags using LibGit2Sharp fails - libgit2sharp

I am trying to fetch all tags of a repository hosted on a private git server and I m getting the following error:
Value cannot be null. (Parameter 'refspecs')
The code is the following:
using (var repo = new Repository(path))
{
foreach (var tag in repo.Tags)
{
repo.Network.Fetch(sourceRepository.Url, null, new FetchOptions { TagFetchMode = TagFetchMode.All });
}
}
How do I get the refspecs so that I can pass them to the Fetch method?

Related

How to Git Fetch <remote> using libgit2sharp?

My existing Fetch method looks like this.
public void Fetch(string remote) => CommandLine.Run($"git fetch {remote}", _repoFolder);
I would like to implement the same feature using libgit2sharp.
This is what I have came up with:
public void Fetch(string remote)
{
var repo = new Repository(_folder);
var options = new FetchOptions();
options.Prune = true;
options.TagFetchMode = TagFetchMode.Auto;
var refSpecs = $"+refs/heads/*:refs/remotes/{remote}/*";
Commands.Fetch(repo, remote, new [] {refSpecs}, options, "Fetching remote");
}
However this fails with the following error message:
System.InvalidOperationException: 'authentication cancelled'
I have also tried with the libgit2sharp-ssh package, where the result is error code 401 (unathorized client).
I presume the git command line tool works because it knows how to authorize the access (since there is already a remote). How can I achieve the same using libgit2sharp?
Have you tried something like
using(var repo = new Repository(_folder))
{
var options = new FetchOptions();
options.Prune = true;
options.TagFetchMode = TagFetchMode.Auto;
options.CredentialsProvider = new CredentialsHandler(
(url, usernameFromUrl, types) =>
new UsernamePasswordCredentials()
{
Username = "username",
Password = "password"
});
var remote = repo.Network.Remotes["origin"];
var msg = "Fetching remote";
var refSpecs = remote.FetchRefSpecs.Select(x => x.Specification);
Commands.Fetch(repo, remote.Name, refSpecs, options, msg);
}

How to get the Commits against a VSTS WorkItem that uses Git as source control

I have a VSTS project that uses Git for source control. The project has multiple repositories (11 to be precise) each with multiple branches.
Given a VSTS Id I am trying to get a list of all the Commits that are associated with that Id.
I am currently coding as follows
VSTSHelper helper = new VSTSHelper(); // my helper for establishing a connection
ProjectHttpClient projectClient = helper.Connection.GetClient<ProjectHttpClient>();
GitHttpClient gitClient = helper.Connection.GetClient<GitHttpClient>();
Microsoft.TeamFoundation.Core.WebApi.TeamProject project = projectClient.GetProject(helper.Project).Result;
List<GitRepository> gitRepositoryList = gitClient.GetRepositoriesAsync(project.Id).Result;
GitQueryCommitsCriteria criteria = new GitQueryCommitsCriteria()
{
IncludeWorkItems = true
};
foreach (GitRepository repo in gitRepositoryList)
{
List<GitBranchStats> branchStatsList = gitClient.GetBranchesAsync(repo.Id).Result;
foreach (GitBranchStats branchStats in branchStatsList)
{
criteria.ItemVersion = new GitVersionDescriptor() { Version = branchStats.Name, VersionType = GitVersionType.Branch };
List<GitCommitRef> commits = gitClient.GetCommitsAsync(repo.Id, criteria).Result;
if (commits.Count > 0)
{
List<GitCommitRef> commitsWithWorkItems = commits.Where(pc => pc.WorkItems.Count > 0).ToList();
if (commitsWithWorkItems.Count > 0)
{
// WorkItemIds is a list of int
List<GitCommitRef> workItemCommits = projectCommitsWithWorkItems.Where(
pc => pc.WorkItems.Any(x => this.WorkItemIds.Contains(Convert.ToInt32(x.Id)))).ToList();
// get the changes associated with the commit here
if (workItemCommits.Count > 0)
{
foreach (GitCommitRef wiCommit in workItemCommits)
{
GitCommitChanges wiChanges = gitClient.GetChangesAsync(wiCommit.CommitId, repo.Id).Result;
}
}
}
}
}
}
The work item id that is passed to my code (e.g Id = 810) has code that was originally committed against another Work Item Id (e.g. 675) in a different branch and then moved to the given Id. The code was then edited and then committed against the new Id (810)
My code above only ever finds the original commit against item 675 - and all the code changes are shown against this Id - including those that I was expecting to see against 810. Nothing is ever returned for Id 810.
Despite lots of googling I find myself struggling big time and I presume that I am misunderstanding some big time!
Any help or pointers in the right direction would be greatly appreciated.
You can use below code to get all the commits which link to a given work item:
As the REST API GET a work item with Fully expanded, all the links information exist under relations object. Then you can get the commits by filtering the url which contains vstfs:///Git/Commit.
int id = workitemID;
var token = "PAT";
String Uri = "https://account.visualstudio.com/DefaultCollection";
var Connection1 = new VssConnection(new Uri(Uri), new VssBasicCredential(string.Empty, token));
WorkItemTrackingHttpClient workItemTrackingClient = Connection1.GetClient<WorkItemTrackingHttpClient>();
WorkItem workitem = workItemTrackingClient.GetWorkItemAsync(id, expand: WorkItemExpand.All).Result;
Console.WriteLine("Related commits contain: ");
foreach (var relation in workitem.Relations)
{
if (relation.Url.Contains("vstfs:///Git/Commit"))
{
Console.WriteLine("commit: {0}", relation.Url);
}
}
To Get the commit sha-1 value (commit ID), it's located in the last 40 characters of the relation.Url which separate with repository ID by %2f. So the url format actually is vstfs:///Git/Commit/{projectID}%2f{repositoryID}%2f{commitID}.
Such as for a relation.Url as below:
vstfs:///Git/Commit/f7855e29-6f8d-429d-8c9b-41fd4d7e70a4%2fad3acf8e-b269-48e5-81bc-354251856b51%2fb802c91e68f321676fe31eca9dda048e7032ea11"
The commit sha-1 value is b802c91e68f321676fe31eca9dda048e7032ea11.
The repository ID is ad3acf8e-b269-48e5-81bc-354251856b51.
The project ID is f7855e29-6f8d-429d-8c9b-41fd4d7e70a4.

History log in sub directory

I'm trying to figure out how to get the commit log for a sub directory. According to this thread, it should work fine in libgit2sharp.
For testing I'm using a small repo, https://github.com/ornatwork/nugetpackages.git that has 8 total entries for the whole repository.
I cloned it locally in root c:/nugetpackages, from that folder I can do.
git log -- devbox
on the command line and I will get two commit entries for the /devbox sub directory as expected.
Sample Xunit test code to do the same using libgit2sharp
[Fact]
public void testSub()
{
// Extract the git commit history
using (var repo = new Repository(#"C:\nugetpackages"))
{
Trace.WriteLine("repo count=" + repo.Commits.Count());
// absolute path
IEnumerable<LogEntry> history = repo.Commits.QueryBy(#"C:\nugetpackages\devbox");
Trace.WriteLine("subdir count=" + history.Count());
}
}
I'm expecting count of 8 and 2, but this is what I get.
repo count=8
subdir count=0
What am I missing ?
Use a relative path from the repository's base diretory:
using (var repo = new Repository(#"/Users/sushi/code/sushi/Xamarin.Forms.Renderer.Tests"))
{
D.WriteLine("repo count=" + repo.Commits.Count());
IEnumerable<LogEntry> history = repo.Commits.QueryBy(#"AlarmSO");
D.WriteLine("subdir count=" + history.Count());
}
ref: FileHistoryFixture.cs
Update:
Follow up, is there a way to combine subdir with a filter, for example. CommitFilter filter = new CommitFilter(); filter.FirstParentOnly = true;
Not sure if this is what you are looking for... if not please in a new question, thanks.
using (var repo = new Repository(#"/Users/sushi/code/sushi/RealmJson"))
{
var subDir = "media";
var commits = repo.Commits.QueryBy(new CommitFilter { FirstParentOnly = true }).Where(
(Commit c) => c.Tree.Any(
(TreeEntry te) => te.Path.StartsWith(subDir, StringComparison.Ordinal)));
foreach (var commit in commits)
{
D.WriteLine($"{commit.Sha} : {commit.MessageShort}");
}
}

Can't update from a remote repository after having local changes

I'm currently trying to update my local repository from a remote one.
This works as long as I don't have any local changes in my files.
using (var r = new LibGit2Sharp.Repository(repo))
{
var options = new MergeOptions
{
MergeFileFavor = MergeFileFavor.Theirs,
};
var result = r.Network.Pull(localSignature, new PullOptions { MergeOptions = options });
}
I found that answer before: StackOverflow.
However, while trying this with the above code, it's just marking my repo as "Up2Date" (status of the result) instead of actually merging my local changes with the remote updates.
How can I actually achieve this?

How can one supply credentials during a Fetch call?

We're not talking about SSH since it's not yet implemented, but how can I supply credentials for the repository before I perform a fetch via HTTP/HTTPS? There doesn't seem to be a parameter for a Credentials instance, and nothing when constructing a Repository instance for storing credentials.
Within the FetchFixture.cs file, there is a Fetch() test using credentials:
[SkippableFact]
public void CanFetchIntoAnEmptyRepositoryWithCredentials()
{
InconclusiveIf(() => string.IsNullOrEmpty(Constants.PrivateRepoUrl),
"Populate Constants.PrivateRepo* to run this test");
string repoPath = InitNewRepository();
using (var repo = new Repository(repoPath))
{
Remote remote = repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl);
// Perform the actual fetch
repo.Network.Fetch(remote, new FetchOptions
{
Credentials = new Credentials
{
Username = Constants.PrivateRepoUsername,
Password = Constants.PrivateRepoPassword
}
});
}
}

Resources