Trees and Blobs
What
In Git’s internal architecture, directories and files are represented by two distinct types of objects:
- Blob (Binary Large Object): Stores only the raw data contents of a file. It does not store file metadata, such as the filename, directory path, or permissions.
- Tree: Represents a directory. It acts as a mapping table, storing a list of pointers to its child files (blobs) and subdirectories (other trees), along with their permissions, types, and actual names.
How
When you inspect a commit object using git cat-file -p, you won’t see file contents directly. Instead, you see a pointer to a root tree object:
# Pretty-print a commit object
git cat-file -p <commit_hash>
# Output:
# tree 4e507fdc6d9044ccd8a4a3061324c9f711c4667d
# author ...
# committer ...
If you pretty-print the root tree hash, you will see a list of its entries:
# Pretty-print the tree object
git cat-file -p 4e507fd
# Output:
# 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 contents.md
Finally, to read the content of the file, you inspect the file’s specific blob hash:
# Pretty-print the blob object
git cat-file -p e69de29
# Output:
# (The actual content of contents.md)
Why
By separating file content (blobs) from directory structures (trees), Git achieves massive structural efficiency. If a file’s content doesn’t change, its blob hash remains identical. Even if the file is moved, renamed, or copied, Git doesn’t need to create a new file on disk; it simply references the same blob hash from a different tree object.
Summary
Blobs store raw file contents, while trees act as directory tables mapping filenames and permissions to their respective blob or subdirectory tree hashes.