Question

I got another libgit2 issue and will be very grateful for your help.

I'm trying to retrieve file history, i.e. list of commits where this file was changed. And it seems to be quite unconventional... As far as I can see, there are no function for that.

The only approach I can come up with is to use revision walking API to iterate through revisions, check the tree object attached to commit and search for given file there, if found, add commit to my list, otherwise proceed to next commit.

But it looks none-optimal for me...

May be is there any other approach, for example, look directly into .git folder and get needed information there?

Many thanks in advance!

Was it helpful?

Solution

But it looks none-optimal for me...

Your approach is the correct one. Beware that you'll have to fight against:

  • Plain renaming (same object Hash, different tree entry name)
  • Renaming and content updation occuring in the same commit (Different hash, different tree entry name. Would require file content analysis and comparison feature which is not available in libgit2)
  • Multiple parents history (two branches which have been merged and into which the same file has been modified in a different way)

May be is there any other approach, for example, look directly into .git folder and get needed information there?

Even though understanding the .git folder layout is always a well-spent time, I'm afraid this won't help you with this specific file history issue.

Note: this question is very close from this libgit2sharp issue: How to get the last commit that affected a given file?

Update

Pull request #963 adds this very feature.

It's available since LibGit2Sharp.0.22.0-pre20150415174523 pre-release NuGet package.

OTHER TIPS

This is mainly followed in issues/495 of libgit2.
Even though it is implemented in libgit2sharp (PR 963, for milestone 22), it is still "up for grabs" in libgit2 itself.

The issue is documented in issues/3041: Provide log functionality wrapping the revwalk.
The approach mentioned in the question was used in this libgit2sharp example and can be adapted to C using libgit2. It remains the current workaround, pending the resolution of 3041.

If using C#, this functionality has been added to the LibGit2Sharp 0.22.0 NuGet Package (Pull Request 963). You can do the following:

var fileHistory = repository.Commits.QueryBy(filePathRelativeToRepository);
foreach (var version in fileHistory)
{
    // Get further details by inspecting version.Commit
}

In my Diff All Files VS Extension (which is open source so you can view the code), I needed to get a file's previous commit so I can see what changes were made to a file in a given commit. This is how I retrieved the file's previous commit:

/// <summary>
/// Gets the previous commit of the file.
/// </summary>
/// <param name="repository">The repository.</param>
/// <param name="filePathRelativeToRepository">The file path relative to repository.</param>
/// <param name="commitSha">The commit sha to start the search for the previous version from. If null, the latest commit of the file will be returned.</param>
/// <returns></returns>
private static Commit GetPreviousCommitOfFile(Repository repository, string filePathRelativeToRepository, string commitSha = null)
{
    bool versionMatchesGivenVersion = false;
    var fileHistory = repository.Commits.QueryBy(filePathRelativeToRepository);
    foreach (var version in fileHistory)
    {
        // If they want the latest commit or we have found the "previous" commit that they were after, return it.
        if (string.IsNullOrWhiteSpace(commitSha) || versionMatchesGivenVersion)
            return version.Commit;

        // If this commit version matches the version specified, we want to return the next commit in the list, as it will be the previous commit.
        if (version.Commit.Sha.Equals(commitSha))
            versionMatchesGivenVersion = true;
    }

    return null;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top