7

I need to programmatically get the last author of a specific line in the Git history with C#. I tried using libgit2sharp :

var repo = new LibGit2Sharp.Repository(gitRepositoryPath);
string relativePath = MakeRelativeSimple(filename);
var blameHunks = repo.Blame(relativePath);
// next : find the hunk which overlap the desired line number

But this is the equivalent of the command

git blame <file>

And in fact I need

git blame -w <file> (to ignore whitespace when comparing)

Libgit2sharp do not set the -w switch and don't provide any parameter/option to set it. What are my options ? Do you know any other library compatible with the -w switch of the blame command ?

Community
  • 1
  • 1
JYL
  • 8,228
  • 5
  • 39
  • 63
  • Just to clarify you have tried NGit? – Jeremy Thompson Apr 04 '16 at 06:07
  • @Jeremy : not at all, I didn't know NGit. I spent so much time on this question that I prefered ask for feedback. – JYL Apr 04 '16 at 12:12
  • Cool, this is a really good feature request for the LibGit2Sharp dev team :) If you ask them politely referencing a link to this Q, you might encourage one of the core team or a contributor to add it while this Q has an active bounty attached... Otherwise Evk should get it (+1). Fingers crossed that's enough to persuade because then you wouldn't need to rely on 2 libraries. – Jeremy Thompson Apr 04 '16 at 12:18
  • @Jeremy : the feature request is already [here](https://github.com/libgit2/libgit2sharp/issues/1177) (since Aug 2015). – JYL Apr 04 '16 at 19:43
  • The problem with lib2gitSharp is that it is using lib2git, which is "a portable, pure C implementation of the Git core methods provided as a re-entrant linkable library with a solid API, allowing you to write native speed custom Git applications in any language which supports C bindings." which doesn't have the whitespace option. It doesn't execute git, so you can add -w, it implements everything. I tried to implement it myself, but C code makes me dizzy. Probably you will have to do with NGIT. – Siderite Zackwehdex Apr 08 '16 at 04:11

3 Answers3

4

When I hit similar advanced scenarios where the git lib isn't cutting it, I just shell out using start process to the real git command line. It's not sexy, but it's mighty effective.

robrich
  • 13,017
  • 7
  • 36
  • 63
  • I though about that before, but I need to do this for about 2000 files in my solution, and feared on performance. I'll try it as a last resort. – JYL Apr 06 '16 at 13:22
  • In fact this way is really faster than using libGit2Sharp in my case. With a test repository of 818 files (4570 commits), with a blame on each file: using direct process : average of 181 ms. per blame ; using ligGit2Sharp : average of 1235 ms per blame. – JYL Apr 14 '16 at 13:50
  • necro posting because this is still the #1 hit for this question. It is now 2019 and the blame implementation in libgit2 is still an order of magnitude slower than command line git according to https://github.com/libgit2/libgit2/issues/3027 – Ammo Goettsch Apr 05 '20 at 23:24
3

Maybe using NGIT library will help. That is direct (automatic) port of java JGIT library. Install via nuget package, then:

    static void Main() {
        var git = Git.Init().SetDirectory("C:\\MyGitRepo").Call();            
        string relativePath = "MyFolder/MyFile.cs";            
        var blameHunks = git.Blame().SetFilePath(relativePath).SetTextComparator(RawTextComparator.WS_IGNORE_ALL).Call();
        blameHunks.ComputeAll();
        var firstLineCommit = blameHunks.GetSourceCommit(0);
        // next : find the hunk which overlap the desired line number
        Console.ReadKey();
    }

Note SetTextComparator(RawTextComparator.WS_IGNORE_ALL) part.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • Thanks for the answer, I'll try this the next week. – JYL Apr 04 '16 at 12:15
  • No way to make this working. Some commits are nice, and some others are just null. Especially when there are whitespace differences. I don't know if I have a wrong or missing option, or if it's just due to the outdated sources of ngit (compared to jgit). I give up, I'm going back to basics (robrich solution). – JYL Apr 11 '16 at 15:07
  • Nevertheless I give you the bounty because the answer is theoretically correct and is given with an appropriate code sample. Thanks. – JYL Apr 11 '16 at 15:13
1

Unfortunately, libgit2sharp is too slow on extracting blames and using this feature is impractical in real scenarios. So, the best way I think is to employ a Powershell script to use the underlying superfast native git. And then redirect the result to your application.

git blame -l -e -c {commit-sha} -- "{file-path}" | where { $_ -match '(?<sha>\w{40})\s+\(<(?<email>[\w\.\-]+@[\w\-]+\.\w{2,3})>\s+(?<datetime>\d\d\d\d-\d\d-\d\d\s\d\d\:\d\d:\d\d\s-\d\d\d\d)\s+(?<lineNumber>\d+)\)\w*' } | 
foreach { new-object PSObject –prop @{  Email = $matches['email'];lineNumber = $matches['lineNumber'];dateTime = $matches['dateTime'];Sha = $matches['sha']}}
Ehsan Mirsaeedi
  • 6,924
  • 1
  • 41
  • 46