Home/Learn/Git/Git Internals — How Git Really Works

Git Internals — How Git Really Works

Beginner
Beginner

Git stores everything as four object types in a content-addressable store: blobs (file content), trees (directories), commits (snapshots), and tags. Every object is identified by its SHA-1 hash.

Overview

Most developers use Git for years without understanding its internals, then hit a confusing situation (detached HEAD, lost commit, weird merge) and have no mental model to reason from. Git's storage model is elegant: it is a key-value store where the key is a SHA-1 hash of the content and the value is the object itself. This means identical content is stored once, history is tamper-evident (changing any byte changes the hash), and every object is self-verifying. Once you understand blobs, trees, commits, and refs, every Git command makes intuitive sense.

The Four Object Types

Git has exactly four object types. A blob stores raw file content (no name, no permissions). A tree stores a directory listing — names, permissions, and pointers to blobs or other trees. A commit stores a pointer to a root tree, parent commit(s), author info, timestamp, and your message. A tag is a named pointer to any object (usually a commit).

Inspecting Git objects directly
// Look inside Git's object store
ls .git/objects/
# 4a/ 9c/ f2/ info/ pack/

# See the type and content of any object by its hash
git cat-file -t 4a7f3b2c   # → blob
git cat-file -p 4a7f3b2c   # → "function login() { ... }"

git cat-file -t 9c2d8e1f   # → tree
git cat-file -p 9c2d8e1f
# 100644 blob 4a7f3b2c  auth.js
# 100644 blob 7e9f1a0b  index.js
# 040000 tree 2b4c8d6e  components/

git cat-file -t f2a1c9b3   # → commit
git cat-file -p f2a1c9b3
# tree    9c2d8e1f
# parent  3a5b2c1d
# author  Akshay <a@example.com> 1704067200 +0530
# committer Akshay <a@example.com> 1704067200 +0530
#
# Add login validation

The Commit DAG

Commits form a Directed Acyclic Graph (DAG) — each commit points to its parent(s). Branches are just named pointers (refs) to commits. HEAD is a pointer to the currently checked-out branch or commit. This is why branching in Git is free — creating a branch just writes a 41-byte file.

The commit DAG and refs
//  Git commit history as a DAG
//
//         HEAD
//          │
//      main branch           feature branch
//          │                      │
//          â–¼                      â–¼
//   ┌─────────┐           ┌─────────┐
//   │ commit  │◄──────────│ commit  │
//   │ a3f8c12 │           │ 7b2e441 │
//   â””────┬────┘           â””────┬────┘
//        │                     │
//        ▼                     │
//   ┌─────────┐               │
//   │ commit  │◄──────────────┘
//   │ 9d2e441 │  (common ancestor)
//   â””────┬────┘
//        │
//        â–¼
//   ┌─────────┐
//   │ commit  │
//   │ 1a2b3c4 │  (initial commit, no parent)
//   â””─────────┘

# A branch is just a file containing a commit hash:
cat .git/refs/heads/main
# → a3f8c12e9d2e441...

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

Content-Addressable Storage

Git uses SHA-1 (transitioning to SHA-256) to hash every object. The same content always produces the same hash — identical files across branches are stored once. This also means you cannot change history without changing all subsequent hashes, making Git history tamper-evident.

Content-addressable storage
# Git hashes are deterministic — same content, same hash
echo "hello world" | git hash-object --stdin
# → 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
# (always the same hash for "hello world
", on any machine)

# This is why "git gc" can deduplicate objects:
# Two branches with the same file share one blob object

# Verify an object hasn't been corrupted:
git fsck --full

# SHA-1 collision resistance means:
# If someone tampers with a commit, its hash changes,
# which changes all child commit hashes → immediately detectable

Key Points to Remember

  • 1Four object types: blob (file content), tree (directory), commit (snapshot + metadata), tag (named pointer)
  • 2Every object is identified by SHA-1 hash of its content — same content = same hash, stored once
  • 3Commits form a DAG — each commit points to parent(s), never backward
  • 4Branches and HEAD are just files containing a 40-character SHA-1 hash — that's why branching is instant
  • 5git cat-file -t <hash> and git cat-file -p <hash> let you inspect any object directly

Interview Questions

Sign in to ask Aria
1

What are the four object types in Git? What does each store?

Medium
2

What is a Git branch internally? Why is creating a branch in Git "cheap"?

Medium
3

What is the difference between HEAD and a branch?

Medium
4

What does "detached HEAD" mean and how does it happen?

Hard

Ask Aria about Git Internals — How Git Really Works

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…