Git Internals (objects, refs)

Difficulty: Advanced

Question

Explain Git's internal object model. What are blobs, trees, and commit objects? How does Git store data?

Answer

Git is fundamentally a content-addressable filesystem. Every piece of data is stored as an object identified by its SHA-1 hash. There are four types of objects:

1. Blob: Stores file contents (no filename, no metadata). Two files with identical content share the same blob. 2. Tree: Represents a directory. Contains pointers to blobs (files) and other trees (subdirectories), along with filenames and permissions. 3. Commit: Points to a tree (the project snapshot), parent commit(s), author, committer, timestamp, and message. 4. Tag: An annotated tag object pointing to a commit with additional metadata.

Refs are human-readable names that point to commit hashes. Branches are refs in .git/refs/heads/, tags in .git/refs/tags/, and remotes in .git/refs/remotes/. HEAD is a special ref that points to the current branch (or directly to a commit in detached HEAD state).

Git stores objects initially as loose objects (one file per object in .git/objects/). Periodically, Git packs them into pack files for efficiency, using delta compression to store only differences between similar objects.

Code examples

Exploring Git Objects

# See the type of any object
git cat-file -t HEAD
# commit

# See the content of a commit object
git cat-file -p HEAD
# tree 4b825dc642cb6eb9a060e54bf899d4e769ad93a2
# parent a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
# author John <john@example.com> 1705312200 +0000
# committer John <john@example.com> 1705312200 +0000
#
# feat: add user authentication

# See the tree object (directory listing)
git cat-file -p HEAD^{tree}
# 100644 blob abc123... .gitignore
# 100644 blob def456... package.json
# 040000 tree 789abc... src

# See a blob (file contents)
git cat-file -p abc123
# node_modules/
# .env
# dist/

# Get the hash of any content
echo "hello" | git hash-object --stdin
# ce013625030ba8dba906f756967f9e9ca394464a

git cat-file is the Swiss Army knife for inspecting objects. -t shows the type, -p shows the content. Every object is identified by its SHA-1 hash.

Understanding Refs

# HEAD points to the current branch
cat .git/HEAD
# ref: refs/heads/main

# Branch is just a file containing a commit hash
cat .git/refs/heads/main
# a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0

# Tags are also refs
cat .git/refs/tags/v1.0.0
# e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0v1w2x3

# Remote tracking branches
cat .git/refs/remotes/origin/main
# a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0

# Symbolic refs
git symbolic-ref HEAD
# refs/heads/main

# Detached HEAD: HEAD points directly to a commit
git checkout a1b2c3d
cat .git/HEAD
# a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
# (no "ref:" prefix = detached)

# Packed refs (optimization for many refs)
cat .git/packed-refs
# a1b2c3d... refs/tags/v1.0.0
# e4f5g6h... refs/remotes/origin/main

Branches are simply files containing commit hashes. This is why branching in Git is instant and cheap - it is just writing 40 characters to a file.

Git Storage and Garbage Collection

# See all objects in the repository
git count-objects -v
# count: 150        (loose objects)
# size: 600         (KB of loose objects)
# in-pack: 3200     (objects in pack files)
# packs: 1          (number of pack files)
# size-pack: 1200   (KB of pack files)

# Verify repository integrity
git fsck
# Checking object directories: 100% done.
# Checking objects: 100% done.

# Manually trigger garbage collection
git gc
# Compresses loose objects into pack files
# Removes unreachable objects older than 2 weeks

# See what a reference resolves to
git rev-parse HEAD
# a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0

git rev-parse HEAD~3
# m0n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5c6d7e8f9

# Find objects by partial hash
git rev-parse --short HEAD
# a1b2c3d

# Show object size
git cat-file -s HEAD
# 264

Git's garbage collector packs loose objects and removes unreachable ones. git fsck verifies integrity. Understanding storage helps debug repository issues.

Key points

Concepts covered

Git Objects, Blob, Tree, Commit Object, Refs, SHA-1, Pack Files