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.