3

I am learning git and know that every commit points to a tree, which in turn points to respective blob(s). While performing a git commit, I can see the commit id getting generated. But how do I find the respective tree hash and the blob(s) hash associated with the commit?

Thanks for your response.

4 Answers 4

8

You can use git cat-file -p on the various types of objects.

git-cat-file - Provide content or type and size information for repository objects
...
-p
Pretty-print the contents of <object> based on its type.

Here's an example.

In my repository, the topmost commit is this:

❯ git lg -1
* 87ffcaa: (7 weeks ago) Updated all packages (HEAD -> develop, origin/develop)
| Lasse Vågsæther Karlsen <[email protected]> (Tue, 16 Jun 2020 12:30:21 +0200)

In order to view the contents of that commit I can execute this:

❯ git cat-file -p 87ffcaa
tree dedfc8120583a89936cacf2e55c5db1d6d532129
parent def5a89a442d0ec88243a43ca9c9fef493dbf4c6
author Lasse Vågsæther Karlsen <[email protected]> 1592303421 +0200
committer Lasse Vågsæther Karlsen <[email protected]> 1592303421 +0200

Updated all packages

Now, if I want to see the tree it references:

❯ git cat-file -p dedfc8120583a89936cacf2e55c5db1d6d532129
100644 blob 9a277a1791951e14c235243bcf374ee2d01e27b9    .editorconfig
100644 blob 1ff0c423042b46cb1d617b81efb715defbe8054d    .gitattributes
100644 blob 304b515a2ae6795ef7c73c6f0d1e822fcefd66b3    .gitignore
040000 tree 74fd33ec96af2b083e9367448bd6f6786e8b4d47    ConsoleSandbox
100644 blob e47b11709137791b3c1241092b3d5215df834ad3    LICENSE
100644 blob 2f2aaad1b5662e3d3e33398c6ce29106d0fbdcac    LVK.sln
100644 blob 9ec3d74ae05f906457f6a60ffa2df78a070ffabb    LVK.sln.DotSettings
100644 blob a1f9a1de838feeec888ab34bf35a998ade9c3560    README.md
040000 tree 759ef337f68ec31f0ca035f9427f309e87765030    SolutionQualityAssuranceTests
...

and if I want to see one of the actual blobs in there, like that LICENSE file:

❯ git cat-file -p e47b11709137791b3c1241092b3d5215df834ad3
MIT License

Copyright (c) 2018 Lasse Vågsæther Karlsen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
...

You can also dig into sub-folders with this. The above tree has this line further down:

040000 tree 408c62b058b6f4b14f65188d492ec452f0bb6e1d    src

which is a subfolder. I can show the tree this references the same way:

❯ git cat-file -p 408c62b058b6f4b14f65188d492ec452f0bb6e1d
100644 blob af6a33f6fe9f8f35d7d070fa16be01319df801bd    Directory.Build.props
040000 tree 9a8adfce1ccb494689fd6710369c1f925fa8acbf    LVK.AppCore.Console
040000 tree 4054753cad506b9a0132c72becd906b388bc8e59    LVK.AppCore.Windows.Forms
...

and so on.

1
  • 1
    Could you add git ls-tree and git ls-files in there? They're handy for recursive listings, for instance git ls-tree -rd @: is a nice structural overview of an entire tree.
    – jthill
    Commented Aug 1, 2020 at 19:04
3

Hope this helps:

blob — object used for storing the contents of a single file.

tree — object which contains references to other blobs or subtrees.

commit — object which contains the reference to another tree object

A commit objects refers to a tree object which refers to blob or other sub-tree objects

  • tree view of commits git log --graph --oneline --all

  • shows various types of objects (blobs, trees, tags and commits) git show <object>

  • lists the contents of a given tree object git ls-tree <object>

  • view the contents, type of objects (COMMIT in your case) git cat-file -p <SHA_OF_ COMMIT_OBJECT>

3

To find out what exact hash any revision expression resolves to, use git rev-parse, whose name hints at its full purpose, as a complete options-and-args parsing toolkit for Git-extending commands.

See git revisions for all the ways you can specify things that resolve to Git id's.

There are a lot of them, because while Git's underlying structure is (all but literally incredibly) simple, the number of things that can (and development work demands) be done with it is endless, and dizzying, and there are a lot of conveniences to make supporting specific workflows more, well, convenient.

If somecommit refers to a commit or a tag, somecommit: refers to the (tagged) commit's tree, as does somecommit^{tree} for those occasions where the bare : might get missed by inspection.

A following : is generally the "get me to a tree" syntax, (leading : is "get me to the index").

To list a tree, use git ls-tree. A quick structural overview is e.g. git ls-tree -rd @:

To list the index, git ls-files, which has a lot of handy options; it's basically the swiss-army knife of index-aware file listing, or perhaps the entire swiss army, maybe that's just me being a teensy bit hyperbolic.

So if somecommit:path/to/file is whatever's listed in that commit at that path, :path/to/file is whatever's listed in your index at that path. There's lots more, see that link.

And since somecommit: names some commit's tree, git rev-parse somecommit: will show you its id; :path/to/file names the index entry for that path, git rev-parse :path/to/file will show you the¹ content id in that entry.


¹ For in-flight merges Git keeps three entries, one for each of the base, ours, theirs content, so you and your tools, including Git's own automerge, can examine the differences, eventually adding the correct result and updating the main index entry. Git somewhat inscrutably calls these "stages", and you can refer to them explicitly with :1:path/to/file and similarly for 2 and 3. The main entry is stage 0.

-2

I recommend reading Git-Internals-Git-Objects. I believe it should answer your question.

Not the answer you're looking for? Browse other questions tagged or ask your own question.