Skip to content

๐Ÿ”ฌ Chapter 13: Git Internals โ€” Behind the Curtain โ€‹

Git's Three Types of Objects โ€‹

Git's core is actually very simple โ€” it's essentially a key-value database. All data is stored as three types of objects:

text
Git's three core objects:

blob (data object):    Stores file content
tree (tree object):    Stores directory structure (file name + blob mapping)
commit (commit object): Stores commit info (author, time, message + pointer to tree)

Their relationship:
commit โ†’ tree โ†’ blob
  โ”‚        โ”‚       โ”‚
  โ”‚        โ”‚       โ””โ”€โ”€ Actual file content
  โ”‚        โ””โ”€โ”€ Directory structure and file names
  โ””โ”€โ”€ Commit metadata + pointer to previous commit
bash
# View Git objects
git cat-file -t HEAD
commit

# View commit object content
git cat-file -p HEAD
tree a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7
parent b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1
author Alice <alice@example.com> 1624182600 +0800
committer Alice <alice@example.com> 1624182600 +0800

feat: add welcome message

# View tree object
git cat-file -p a8b9c0d1
100644 blob f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6    index.html
100644 blob e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5    style.css

# View blob object
git cat-file -p f7a8b9c0
<!DOCTYPE html>
<html>
<head>
  <title>My First Website</title>
</head>
<body>
  <h1>Hello, Git!</h1>
  <p>Welcome to my website!</p>
</body>
</html>

SHA-1 Hash โ€” Git's Identity System โ€‹

Git uses SHA-1 hash values to identify each object. The same content always produces the same hash.

bash
# Git calculates blob hash values like this
# Format: blob <content length>\0<actual content>

echo -n "Hello, Git!" | git hash-object --stdin
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 (example, actual value varies by environment)

# Same calculation every time (deterministic)
echo -n "Hello, Git!" | git hash-object --stdin
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 (example, actual value varies by environment)

# Change one character, completely different hash (avalanche effect)
echo -n "Hello, git!" | git hash-object --stdin
b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1 (example, actual value varies by environment)

Refs โ€” Human-Readable Pointers โ€‹

SHA-1 hashes are too hard for humans to remember, so Git uses "refs" to give them names.

bash
# A branch is just a pointer to a commit
cat .git/refs/heads/main
f4e5d6c7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3

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

# Remote branch refs
cat .git/refs/remotes/origin/main
a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6

# The complete reference chain:
# HEAD โ†’ refs/heads/main โ†’ commit hash โ†’ tree โ†’ blobs

Packfiles โ€” Git's Compression Technique โ€‹

Although Git saves snapshots, it doesn't fully copy all files every time. When there are many files, Git automatically packs and compresses them.

bash
# Manually trigger garbage collection and packing
git gc
Enumerating objects: 42, done.
Counting objects: 100% (42/42), done.
Delta compression using up to 8 threads
Compressing objects: 100% (30/30), done.
Writing objects: 100% (42/42), done.
Total 42 (delta 12), reused 42 (delta 12), pack-reused 0

# View repository size
git count-objects -vH
count: 0
size: 0 bytes
in-pack: 42
packs: 1
size-pack: 8.50 KiB
prune-packable: 0
garbage: 0
size-garbage: 0 bytes