How to find the branch a git commit is on? (Using libgit2sharp)
Asked Answered
R

3

8

For a research project, I've been trying to replicate the graph view present in version control software like SourceTree or TortoiseGit.

The graph view I'm trying to implement The graph view I'm trying to implement

The biggest problem I'm having is finding what branch a commit belongs to. If I have this, I can assign the commit dot a column and a color. This is difficult because under the hood, Git doesn't store the branch the commit was initially on.

Looking at other solutions on StackOverflow, I found it is possible to get a list of branches that contain the commit, but I need a method of isolating a single one to display in my graph. In the same way SourceTree or TortoiseGit somehow manage to do it.

My problem is also identical to this one, Find out the branch a commit belongs to in LibGit2Sharp?

It looks like they discovered the actual solution in a private discussion room. However, I don't have the reputation to comment and ask what they found.

Does anyone have any ideas on how I could do this?

Or, @nulltoken if by chance you see this and remember, do you know what you guys discovered in that discussion room?

Roseannroseanna answered 14/11, 2017 at 3:4 Comment(3)
The discussion in chat is not private: chat.stackoverflow.com/rooms/8237/…Matrimonial
The normal solution to this is to record the information via git notes attached to the commit. If you are using gerrit it does this for you automatically, if not you'd need to write a hook.Shiftless
@EdwardThomson Oh.. that looks like a incorrect assumption on my part.. whoops! Are you able to look at the contents of the chat by chance? I get a "Page not found" error...Roseannroseanna
R
1

It turns out to generate the graph, SourceTree doesn't need to know what branch a commit is on.

The first commit in the graph always has a column of 0. Also, it's possible to get a list of parent commits of a given commit. By starting with the first commit and iterating backwards, they can generate a nice looking graph by only using this info.

Roseannroseanna answered 10/5, 2018 at 22:2 Comment(0)
G
2

Not sure how much of helpful this answer would prove to you. The LibGit2Sharp equivalent call for "git branch --contains $SHA1" is a requested feature on GitHub, an open one!

Long back, I used a query over all refs like this, but for your use-case it might be prohibitively slow.

I was trying to think for possible ways to mitigate this problem, could not come up with any guiding light. :( And then I discovered this comment which asserts that you need to traverse the DAG and validate the actual branch which has the commit. It all hints that you would need to go the slow traverse-all-refs approach.

Gobert answered 14/11, 2017 at 7:59 Comment(6)
I think the OP is not asking for traversal or to emulate branch --contains. The OP is asking how to find out the current tips of all refs to decorate them.Matrimonial
(But having re-read this a few times, I can't actually tell, to be quite honest.)Matrimonial
@edward-thomson, exactly! :) after your [such a high reputation person] comment, I read the question around 8 times, but I also couldn't get how you arrived at that conclusion or I arrived at mine! Only this gave me a benefit of doubt: The biggest problem ... and I need a method of isolating...Gobert
I suppose to clarify, I've managed to replicate git branch --contains. The catch is multiple branches can contain the same commit. This makes it hard to choose one to display as "owning that commit" in my graph (e.g. whether it belonged to NewBranch2 or master). e.g. If I created branch "A" from "master", did some work on "A", then merged "A" into master, git branch --contains $(any sha from A) would return A, master.Roseannroseanna
In this case, it would obviously be the top result - "A". But if I later branched "B" from "A", git branch --contains $(any sha from A) would return "B, A, master. In this case, "B" is the top result - but the commit was initially on A, so I can't always display the top branch as owning the commit in my graph...Roseannroseanna
Thanks for the clarification @jade-white. You can evaluate the branch which is the exact owner of a commit by reflog. I didn't ned to use this functionality much, and on a quick search I stumbled upon this thread which could help you: https://mcmap.net/q/1472354/-how-to-detect-what-commit-a-branch-has-been-created-from-in-libgit2sharp. Please note that there is a limited history you can search with reflog. Hope that helps.Gobert
R
1

It turns out to generate the graph, SourceTree doesn't need to know what branch a commit is on.

The first commit in the graph always has a column of 0. Also, it's possible to get a list of parent commits of a given commit. By starting with the first commit and iterating backwards, they can generate a nice looking graph by only using this info.

Roseannroseanna answered 10/5, 2018 at 22:2 Comment(0)
C
0

This may be valuable on how to do this when you wish to show more than just the history of HEAD ( which is achieved by enumerating repository.Commits):

repository.Commits
    .QueryBy(new CommitFilter 
    {
        IncludeReachableFrom = repository.Refs.ToList(), // or adjust to your needs
        SortBy = CommitSortStrategies.Time
    })
    .Distinct<Commit>(EqualityComparer<GitObject>.Default)
    .ToList();

copied from / inspired by: https://mcmap.net/q/1472355/-how-to-get-all-git-commits-with-libgit2sharp-regardless-the-branch

When iterating the commits, you check which refs ( including branches ) point to them to show the ref names in the graph.
I'd suggest storing the refs in a Lookup to find which one(s) point to each commit:

ILookup<GitObject, string> refsByCommit = repo.Refs.ToLookup(@ref => @ref.ResolveToDirectReference().Target, @ref => @ref.CanonicalName);
// ( ... )
foreach (var commit in commits)
{
    // ( ... )
    var refNames = refsByCommit[commit];
    // ( ... )
}
Caudill answered 4/8, 2021 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.