Steven
Steven

Reputation: 13995

Get a blob from a commit?

I am trying to figure out how I could get a list of files and their respective old and new blobs for a single commit.

Say you have commit 1 which changed 3 files. I would run said function and return 3 files along with their old blob and new blob (assuming they are not binary).

Would the only way to do this be get the commit and previous commit, resolve their trees, then do a diff on the trees to find out what is different, and then get the blob for every different file?

Upvotes: 4

Views: 1096

Answers (3)

nulltoken
nulltoken

Reputation: 67649

Would the only way to do this be get the commit and previous commit, resolve their trees, then do a diff on the trees to find out what is different, and then get the blob for every different file?

Yes, this is the recommended way. "Old" and "new" entries are only concepts that make sense when comparing two Trees.

Beware that "old" and "new" are not that expressive qualifiers. As one can peek in the diff header, the resulting diffing status of an entry may be

  • GIT_DELTA_UNMODIFIED = 0, /** no changes */
  • GIT_DELTA_ADDED = 1, /** entry does not exist in old version */
  • GIT_DELTA_DELETED = 2, /** entry does not exist in new version */
  • GIT_DELTA_MODIFIED = 3, /** entry content changed between old and new */
  • GIT_DELTA_RENAMED = 4, /** entry was renamed between old and new */
  • GIT_DELTA_COPIED = 5, /** entry was copied from another old entry */
  • GIT_DELTA_IGNORED = 6, /** entry is ignored item in workdir */
  • GIT_DELTA_UNTRACKED = 7, /** entry is untracked item in workdir */
  • GIT_DELTA_TYPECHANGE = 8, /** type of entry changed between old and new */

The libgit2 tests-clar/diff/tree test file should give you some sample usage of this feature.

Update:

A similar question (from you? ;-) ) has been raised in the libgit2 issue tracker. The answer from @arrbee also relies on leveraging the git_diff_tree_to_tree() API.

Upvotes: 3

Greg Bacon
Greg Bacon

Reputation: 139681

Extracting SHA1s for previous and current revisions

Consider the output of git show --raw v1.8.1^0 in git’s own repository.

commit 5d417842efeafb6e109db7574196901c4e95d273
Author: Junio C Hamano 
Date:   Mon Dec 31 14:24:22 2012 -0800

    Git 1.8.1

    Signed-off-by: Junio C Hamano <[email protected]>

:100644 100644 fec1a06... d6f9555... M  Documentation/RelNotes/1.8.1.txt
:100644 100644 b0e8f02... 7a3f03b... M  Documentation/git.txt
:100755 100755 b2dffc8... 72e37c9... M  GIT-VERSION-GEN

The last three lines indicate files that changed with that commit. The first SHA1 on a change line is the object name of the previous revision of a given file, and the second is the blob in the named commit. For example, GIT-VERSION-GEN in v1.8.1 hashes to

$ git show v1.8.1^0:GIT-VERSION-GEN | git hash-object --stdin
72e37c9bfe3e897635f8c211569d9e6f5658a980

and the blob associated with its parent commit is

$ git show v1.8.1^0~:GIT-VERSION-GEN | git hash-object --stdin
b2dffc839f306123d544e8f536ee31a7574f1139

Note: the documentation for git rev-parse explains

As a special rule, <rev>^0 means the commit itself and is used when <rev> is the object name of a tag object that refers to a commit object.

In this case, v1.8.1^0 means the commit to which tag v1.8.1 refers.

Fetching SHA1s for all blobs in a commit

To get object names for all blobs associated with a given commit, read the output of git ls-tree, which resembles

$ git ls-tree -r v1.8.1^0
100644 blob 5e98806c6cc246acef5f539ae191710a0c06ad3f    .gitattributes
100644 blob f702415c12c5a4a66180f7ffd697347e5343ac4a    .gitignore
100644 blob c7e86183001a00ad2105765708b5b59852ef6640    .mailmap
100644 blob 536e55524db72bd2acf175208aef4f3dfc148d42    COPYING
100644 blob ddb030137d54ef3fb0ee01d973ec5cee4bb2b2b3    Documentation/.gitattributes
100644 blob d62aebd848b2a44f977ad4d7c4b75b6ff72b2163    Documentation/.gitignore
100644 blob 69f7e9b76c3f9b87b7951fb0df6a9720edadeb3e    Documentation/CodingGuidelines
100644 blob e53d333e5c08515af1e21d81c7daa365b12609a1    Documentation/Makefile
100644 blob fea3f9935b7794ce86f04d22c9d68fb9d537167d    Documentation/RelNotes/1.5.0.1.txt
100644 blob b061e50ff05b5e13211bb315e240974e898de32c    Documentation/RelNotes/1.5.0.2.txt
...

Upvotes: 0

poke
poke

Reputation: 388223

Using only Git commands, don’t know about the particular libgit2 functions to access this information, but you can probably figure that out.

You can get a file listing of which files have changed in a particular commit using git show --stat COMMIT. At the bottom is a list of file paths that have changed (plus details how many lines changed). You can probably filter out the stuff from there. You can further use the pretty-formatting to remove even more content from the output.

Once you have the file path, you can get a file blob using git show COMMIT:PATH. You get the previous version of the file using git show COMMIT^:PATH.

Upvotes: -1

Related Questions