Libgit2sharp Get remote branches - c#

Maybe asked before, but I cannot find the clear answer. When I need to list the branches of a repo with gitlib2sharp, do I really first need to clone to a local repo? What is the sense in that? I just want to clone a specific branch, like you do with git clone https://bla/repo.git -b branch1
Now I first need to do a local checkout, then get the branches and from there do a second round.
Am I missing something here (hope I do).
TIA for your answer!
Grtz,
Ronald
Update (to long for comment):
OK, so here's the use case. A company delivers ssrs reports, which we need to deploy through TAP. So my thoughts were to do this via Git. For each change let them create a branche, upload/alter/etc in this branche. And iterate changes in this branch till all is fine. In the iterations they should be able to (re)deploy themselves on at least T. At the final stage we merge the brnanch to master and (re)deploy master in P. In Github you can completely 'click' this flow, but of course I want to automate this and have preferably someelse push the buttons, so they don't need me for this. So what's the best programmatic choice here? When they make a branch and start deploying in T, should I create (clone) the repo, point my local repo to the specific branch, get the files (.sql and .rdl files) and execute/upload these? I was not aware that when you clone a repo, you clone all the branches with it. Thanks so far already!

If you want to do something like git clone https://bla/repo.git -b branch1 with libgtk2sharp try this one:
var exampleRepositoryUrl = "https://github.com/npgsql/npgsql.git";
var exampleDestinationFolder = "branch-hotfix-3.0.8";
var exampleBranchName = "hotfix/3.0.8";
var repositoryClonedPath = Repository.Clone(exampleRepositoryUrl,
exampleDestinationFolder,
new CloneOptions()
{
BranchName = exampleBranchName
});
using (var clonedRepo = new Repository(repositoryClonedPath))
{
// ...
}
To list names of remote branches without cloning a repo you can use something like this:
var branches = Repository.ListRemoteReferences(exampleRepositoryUrl)
.Where(elem => elem.IsLocalBranch)
.Select(elem => elem.CanonicalName
.Replace("refs/heads/", ""));

PiKos answer worked for me, but I had to set a credentials handler, e.g.:
var branches = Repository.ListRemoteReferences(exampleRepositoryUrl, MyCredentialsHandler)
.Where(elem => elem.IsLocalBranch)
.Select(elem => elem.CanonicalName
.Replace("refs/heads/", ""));
For more details on how to set a custom credentials handler, see this answer:
https://stackoverflow.com/a/55371988/5507590

Related

How to get a list of remote changes from fetch using LibGit2Sharp

I am able to successfully fetch, pull, push, etc. using LibGit2Sharp, but I would like to be able to list files that have changed, added, etc. after doing a fetch. I'm using https://github.com/libgit2/libgit2sharp/wiki/git-fetch and no errors or exceptions occur and logMessage is an empty string.
I would like to be able to show a list of changes like Visual Studio does when you perform a fetch.
How can I use LibGit2Sharp to accomplish this?
Edit:
I have read through the LibGit2Sharp Wiki and the LibGit2Sharp Hitchhiker's Guide to Git. While I have tried some of the available commands to review what results they offer, I am not sure what the equivalent git command would be for this either. It would be helpful to know and understand which command would provide this information and would be appreciated if you are familiar with Git, but not LibGit2Sharp.
Once the fetch is done, you can list the fetched commit of a given branch with
git log ..#{u}
with #{u} designating the branch you are merging from (the upstream remote tracking branch, generally origin/yourbranch)
In LibGitSharp, that is what LibGit2Sharp/BranchUpdater.cs#UpstreamBranch reference (the upstream branch)
With that, you should be able to list the commmits between your current branch HEAD and "UpstreamBranch", a bit like in issue 1161, but that issue was listing what is being pushed: let's invert the log parameters here.
var trackingBranch = repo.Head.TrackedBranch;
var log = repo.Commits.QueryBy(new CommitFilter
{ IncludeReachableFrom = trackingBranch.Tip.Id, ExcludeReachableFrom = repo.Head.Tip.Id });
var count = log.Count();//Counts the number of log entries
//iterate the commits that represent the difference between your last
//push to the remote branch and latest commits
foreach (var commit in log)
{
Console.WriteLine(commit.Message);
}

How to get all changes to a file in Git, with Lib2GitSharp

I want to be able to Get a list of all changes done to a file. I've seen this post
How to get file's contents on Git using LibGit2Sharp?, but this requires to start off with a commit. I want to start digging with the filename.
Also is this possible without getting the whole repo locally?
After a bit of research I think I found an answer.
/*Small test*/
using (Repository repo = new Repository(strLocalDeliveryPath))
{
var fileHistory = repo.Commits.QueryBy(#"Path/To/file.ini").ToList();
int i = fileHistory.Count();
}
This is in order newest to oldest, and that suits me fine. I would normally only need the latest version of the file content, but nor i have the option of digging through the history of the file.
You can see this answer for a bit more info, but yes, the functionality was added in libgit2sharp 0.22.0. Here's an example:
var fileHistory = repository.Commits.QueryBy(filePathRelativeToRepository);
foreach (var version in fileHistory)
{
// Get further details by inspecting version.Commit
}

Dynamic Workspace.Merge TFS changesets

I'm writing a TFS plugin to automate merging of changesets related to a work item whenever said work item is changed from state "Resolved" to state "Closed". The following code is what I have so far:
C#
private void Action_ResolvedToClosed()
{
//Linq query for getting changesets associated with the current work item
var changeSets = WorkItem.Links
.OfType<ExternalLink>()
.Select(link =>
VersionControlServer.ArtifactProvider.GetChangeset(new Uri(link.LinkedArtifactUri))).ToList();
if (!changeSets.Any())
{
LOG_NOCHANGESETS(WorkItem.Id);
return;
}
Workspace workspace = VersionControlServer.GetWorkspace(<My Workspace>);
var source = URI_LOCAL; // $/<Project Name>/<Working Branch>
var destination = URI_DEV; // $/<Project Name>/<Development Branch>
// Merge applicable changesets
foreach (var versionSpec in changeSets.Select(changeset => new ChangesetVersionSpec(changeset.ChangesetId)))
{
workspace.Merge(source, destination, versionSpec, versionSpec);
workspace.CheckIn(workspace.GetPendingChanges(), "**Automated Merge**");
LOG_SUCCESS(versionSpec.ChangesetId, WorkItem.Id);
}
}
Is there a way to dynamically generate the workspace variable? Odds are I won't be the one actually making changes - the goal is to automate this process for our devs.
UPDATE: I'm pretty sure what I'm looking for in this second part is GetStatus, so it can be ignored. The paragraph above is my real question.
Secondary: I feel like automating merges can't be this simple. What happens if merge conflicts arise? Does Workspace.Merge fail gracefully? Are there any other glaring issues that someone with a bit more experience with the TFS API can point out?
First, it sounds like you want to query the user's workspace cache to get the appropriate Workspace and "realize" it. If
WorkspaceInfo workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(path);
Workspace workspace = workspaceInfo.GetWorkspace(new TfsTeamProjectCollection(workspaceInfo.ServerUri);
However, as you point out, you may prefer to create a temporary workspace. This will ensure that you do not conflict with any changes the user is trying to make in their own workspace. For example:
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://server:8080/tfs/DefaultCollection"));
VersionControlServer vcs = tpc.GetService<VersionControlServer>();
Workspace workspace = vcs.CreateWorkspace("MERGE-TEMP");
workspace.Map("$/Merge-Source", #"C:\Temp\Merge\Source");
workspace.Map("$/Merge-Target", #"C:\Temp\Merge\Target");
Second, if you run into merge conflicts, they will be set in the workspace. You can query the NumConflicts method of the returned GetStatus. (Though you will not be able to Checkin untli you have resolved the conflicts.

Using p4 api .NET to add files to a Changelist

My overall goal is to be able to sync, check out, and check in files within a workspace. This is the main part I am confused about:
IList<FileSpec> files = new List<FileSpec>();
FileSpec file = new FileSpec(testpath, null, locpath, VersionSpec.Head);
files.Add(file);
IList<FileSpec> foundFiles = rep.GetDepotFiles(files, null);
con.Client.SyncFiles(foundFiles, null);
Changelist cl = new Changelist();
cl.Description = "newest change";
cl.ClientId = ws_client;
Changelist changelist = rep.CreateChangelist(cl);
//Added the line below
con.Client.EditFiles(new Options(EditFilesCmdFlags.None, changelist.Id, null), file);
I first create the list of depot files (foundFiles) that I get from the repository, which works fine. I then try to sync these files to the client. I then create a Changelist, but I do not know how to go about editing files and submitting the changes. I am aware of the Client.EditFiles and Changelist.Submit methods, but I am not sure how to utilize them in this situation since I do not fully understand the linkage between a client/workspace and a changelist. In short, I would like to be able to access, edit, and submit files. One main problem is that my Changelist has no files in it and I am predicting that knowing how to add files is the first step. Any help or sample code is greatly appreciated!
I know the question is 2 years old, but the p4api.net documentation is still poor, so any answer might help future users.
I believe your remaining problem is that you use versioned file spec. Your problem should be solved by following last line:
//Added the line below
con.Client.EditFiles(new P4.Options(P4.EditFilesCmdFlags.None, changelist.Id, null), P4.FileSpec.UnversionedSpecList(foundFiles).ToArray());
I don't have a lot of experience with P4API.NET, but I think what you need to do is call Client.EditFiles, and use the options parameter to specify the changelist. Not sure if you'd use a reference to the changelist object, or just the changelist number.

Saving WorkItem#IterationPath on newly created Iteration

I can successfully create an iteration path via:
var commonservice = collection.GetService<ICommonStructureService>();
// create new area path and iteration path
var iterationRoot = commonservice.GetNodeFromPath("\\MyTeamProject\\Iteration");
var newIterationPath = commonservice.CreateNode("my new sprint", iterationRoot.Uri);
However, when I try and assign this path to a work item and save it the field doesn't validate.
If I run the tests again (with the iteration already created) the same code succeeds.
Does anybody know how to make this work?
This fixed it for me:
WorkItemStore wis = (WorkItemStore)tfsTeamProjColl.GetService(typeof(WorkItemStore));
wis.RefreshCache();
wis.SyncToCache();
Maybe it will help someone.
I experienced exactly the same behavior, and unfortunately #JWC answer didn't help. The solution which works for me can be found by this link.
So, this is a quick summary in case the original answer gets lost.
The key point is to use WorkItemServer class. It lives in the Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll assembly.
First of all, you create a WorkItemStore instance:
var store = collection.GetService<WorkItemStore>();
Then, create necessary iteration paths:
var commonservice = collection.GetService<ICommonStructureService>();
var iterationRoot = commonservice.GetNodeFromPath("\\MyTeamProject\\Iteration");
var newIterationPath = commonservice.CreateNode("my sprint", iterationRoot.Uri);
Next, refresh the cache in TFS (I suspect this is similar to pressing F5 in web interface):
var wiServer = collection.GetService<WorkItemServer>();
wiServer.SyncExternalStructures(WorkItemServer.NewRequestId(), commonservice.GetProjectFromName("MyTeamProject").Uri);
store.RefreshCache();
And finally, assign newly created work item to the newly created iteration:
var wi = new WorkItem(store.Projects["MyTeamProject"].WorkItemTypes["Product Backlog Item"]);
wi.Title = "Hello from API";
wi.Description = "This work item was created from API";
wi.Fields["Assigned To"].Value = "Yan Sklyarenko";
wi.IterationPath = FormatPath(commonservice.GetNode(newIterationPath).Path, "Iteration", "MyTeamProject");
wi.Save();
That's it! The method FormatPath translates the iteration path to the form required by the work item IterationPath field, that is from \MyTeamProject\Iteration\my sprint to MyTeamProject\my sprint.
Hope this can save some time.
NOTE: I run this towards TFS 2013.
You are likely running into a caching issue. Try clearing the cache after you create the iteration. A couple things you could try:
Get a new copy of the WorkItemStore.
Disconnect and reconnect to TFS
Check to see if there's a "refresh" method on either the WIS or on the TFS server objects. I've shut down my dev instance of TFS for the night, and I don't recall if there's anything like it.
If that's not quite it, post your code and I'll see if I can reproduce it.
I had the similar issue. I created Areapath and then created a query where the AreaPath was used. I did call store.RefreshCashe() but it did not work. Only in Debugger when I run store.RefreshCashe() two times manually.
Thanks "Yan Sklyarenko". I tried your Suggestion and it works fine (TFS Server 2012).

Categories