Question

How do I get a list of commits which contain a particular file, ie the equivalent of git log path for LibGit2Sharp.

Has it not been implemented or is there a way that I'm missing?

Was it helpful?

Solution

I was working on getting the same functionality into my application with LibGit2Sharp.

I wrote the code below which will list all of the commits that contain the file. The GitCommit class isn't included, but it is just a collection of properties.

My intention was to have the code only list commits where the file had changed, similar to a SVN log, but I haven't written that part yet.

Please note that the code hasn't been optimized, it was merely my initial attempt, but I hope it will be useful.

/// <summary>
/// Loads the history for a file
/// </summary>
/// <param name="filePath">Path to file</param>
/// <returns>List of version history</returns>
public List<IVersionHistory> LoadHistory(string filePath)
{
    LibGit2Sharp.Repository repo = new Repository(this.pathToRepo);

    string path = filePath.Replace(this.pathToRepo.Replace(System.IO.Path.DirectorySeparatorChar + ".git", string.Empty), string.Empty).Substring(1);
    List<IVersionHistory> list = new List<IVersionHistory>();

    foreach (Commit commit in repo.Head.Commits)
    {
        if (this.TreeContainsFile(commit.Tree, path) && list.Count(x => x.Date == commit.Author.When) == 0)
        {
            list.Add(new GitCommit() { Author = commit.Author.Name, Date = commit.Author.When, Message = commit.MessageShort} as IVersionHistory);
        }
    }

    return list;
}

/// <summary>
/// Checks a GIT tree to see if a file exists
/// </summary>
/// <param name="tree">The GIT tree</param>
/// <param name="filename">The file name</param>
/// <returns>true if file exists</returns>
private bool TreeContainsFile(Tree tree, string filename)
{
    if (tree.Any(x => x.Path == filename))
    {
        return true;
    }
    else
    {
        foreach (Tree branch in tree.Where(x => x.Type == GitObjectType.Tree).Select(x => x.Target as Tree))
        {
            if (this.TreeContainsFile(branch, filename))
            {
                return true;
            }
        }
    }

    return false;
}

OTHER TIPS

LibGit2Sharp comes from the C library libgit2... which didn't include git log in the first place ;)

Yet, LibGit2Sharp has its own git log function:
Its page on git log involves Filters, but a Filter doesn't seem to filter by path (as detailed in "How to exclude stashes while querying refs?").
So it doesn't seem to be implemented at the moment.

Each time when tree/blob has been changed it gets new id hash. All you need is to compare with parent commit tree/blob item hash:

var commits = repository.Commits
   .Where(c => c.Parents.Count() == 1 && c.Tree["file"] != null &&
      (c.Parents.FirstOrDefault().Tree["file"] == null ||
         c.Tree["file"].Target.Id !=
         c.Parents.FirstOrDefault().Tree["file"].Target.Id));

Very similar to dmck's answer but more up to date

private bool TreeContainsFile(Tree tree, string filePath)
{
    //filePath is the relative path of your file to the root directory
    if (tree.Any(x => x.Path == filePath))
    {
        return true;
    }

    return tree.Where(x => x.GetType() == typeof (TreeEntry))
        .Select(x => x.Target)
        .OfType<Tree>()
        .Any(branch => TreeContainsFile(branch, filePath));
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top