Skip to content

Git Internals

bparlaker edited this page Oct 6, 2026 · 2 revisions

Git Internals - what is a commit, really?

Most Git confusion disappears once you see that Git is just a content-addressed key-value store plus a few pointers.

1. Four object types

Object Stores Analogy
blob the contents of a file (no name!) a page of text
tree a directory listing: names → blobs/trees a folder
commit one root tree + parent(s) + author + message a snapshot with a label
tag (annotated) a named, signed pointer to a commit a bookmark

Every object is named by the SHA-1 hash of its content (SHA-256 is supported in newer repos). Same content ⇒ same hash ⇒ stored once.

2. See it yourself

mkdir demo && cd demo && git init
echo "hello git" > hello.txt
git add hello.txt
git commit -m "first commit"

git cat-file -t HEAD          # -> commit
git cat-file -p HEAD          # show the commit object

Output (hashes will differ):

tree 07ed5a7aebb914e3a02edf6d622b82d364037e3c
author Berker Parlaker <berker@example.com> 1790680000 +0300
committer Berker Parlaker <berker@example.com> 1790680000 +0300

first commit
git cat-file -p 07ed5a7       # the tree
# 100644 blob 8d0e41234f24b6da002d962a26c2495ea16a425f    hello.txt
git cat-file -p 8d0e412       # the blob
# hello git

You can even compute a blob's hash without Git storing anything:

echo "hello git" | git hash-object --stdin
# 8d0e41234f24b6da002d962a26c2495ea16a425f

3. Commits form a graph (DAG)

Each commit points to its parent(s), so history is a directed acyclic graph:

A <-- B <-- C <-- D   (main)
             \
              E <-- F (feature)

Changing anything in an old commit changes its hash - and therefore the hash of every commit after it. That is why history is tamper-evident, and why rewriting pushed history is disruptive.

4. Branches and HEAD are just tiny files

cat .git/HEAD                 # ref: refs/heads/main
cat .git/refs/heads/main      # 40-char commit hash

A branch is a 41-byte file holding a hash. Creating a branch is therefore instant and nearly free.

5. Cool facts

  • git gc packs objects and stores deltas, so repositories stay small even though Git conceptually stores full snapshots.
  • An empty folder cannot be committed - trees only list things that contain blobs. (Convention: add a .gitkeep file.)
  • git fsck verifies every hash in the repo - corruption can't go unnoticed.

Clone this wiki locally