10

I checked code in BlobFixture.cs and found some tests about reading file's contents like below.

using (var repo = new Repository(BareTestRepoPath))
{
    var blob = repo.Lookup<Blob>("a8233120f6ad708f843d861ce2b7228ec4e3dec6");

    var contentStream = blob.GetContentStream();
    Assert.Equal(blob.Size, contentStream.Length);

    using (var tr = new StreamReader(contentStream, Encoding.UTF8))
    {
        string content = tr.ReadToEnd();
        Assert.Equal("hey there\n", content);
    }
}

But I cannot find a test that getting file's contents based on file's name. Is it possible to do that, if so how?

Anonymous
  • 9,366
  • 22
  • 83
  • 133
  • Add `:your/file/path.txt` to the end of the SHA string as [@nulltoken points out.](https://stackoverflow.com/questions/53264430/download-one-file-from-remote-git-show-using-libgit2sharp#comment93433585_53265220) – Michael Feb 12 '19 at 21:10

1 Answers1

27

Each Tree holds a collection of TreeEntrys. A TreeEntry holds some metadata (name, mode, oid, ...) about a referenced GitObject. The GitObject can be accessed through the Target property of a TreeEntry instance.

Most of the time, a TreeEntry will point to a Blob or another Tree.

The Tree type exposes an indexer which accepts a path to easily retrieve the finally pointed at TreeEntry. As a convenience method, the Commit exposes such an indexer as well.

Thus your code could be expressed this way.

using (var repo = new Repository(BareTestRepoPath))
{
    var commit = repo.Lookup<Commit>("deadbeefcafe"); // or any other way to retrieve a specific commit
    var treeEntry = commit["path/to/my/file.txt"];

    Debug.Assert(treeEntry.TargetType == TreeEntryTargetType.Blob);
    var blob = (Blob)treeEntry.Target;

    var contentStream = blob.GetContentStream();
    Assert.Equal(blob.Size, contentStream.Length);

    using (var tr = new StreamReader(contentStream, Encoding.UTF8))
    {
        string content = tr.ReadToEnd();
        Assert.Equal("hey there\n", content);
    }
}
nulltoken
  • 64,429
  • 20
  • 138
  • 130
  • This sort of works and gets me part of the way there, Thanks! The problem here though is that the commit will only contain the files modified in that commit. I am still looking for a way to get a specific file at specified repo path, regardless of when it was checked it. I also have no way, ahead of time, of knowing the sha1 hash for a particular commit, nor do I really care in this scenario. I will post an answer if I find one. – Dan Csharpster Dec 08 '16 at 23:44
  • 2
    A commit isn't a diffgram. It's a snapshot. As such, it contains all the files that were in the working directory when it was generated. – nulltoken Dec 09 '16 at 07:15
  • From the command line, I found out how to do what I wanted. I can do a sparse checkout of a subdirectory and then do a shallow clone of depth=1 so I only get the history of the head revision. I'm writing some shell commands to call the command line and will post it when its done. – Dan Csharpster Dec 09 '16 at 14:43
  • Great answer. @DanCsharpster (which I understand you most likely have moved on with your life by now) for me the branch commit at the head tip is what I am always looking for, like: string trackedBranchName = $"{ORIGIN_NAME}/{branchToCheckout}"; Branch trackedBranch = m_repo.Branches[trackedBranchName]; string currentBranchTipAtOrigin = trackedBranch.Tip.Id.ToString(); – RoboYak Feb 09 '21 at 03:01