Step 1 A commit is a snapshot, not a diff
Many tools store a file's history as a list of changes. Git stores complete snapshots: each commit records what every tracked file looked like at that moment. Unchanged files are not copied — the commit just re-points at the identical existing content — so snapshots are cheap. The diffs you see in git log are computed by comparing two snapshots, not stored.
Two commits, side by side
Files that did not change between snapshots share the exact same stored object — Git never duplicates identical content.
Step 2 Working tree → staging → repository
A change moves through three areas. You edit files in the working tree, pick which edits to include with git add (the staging area / index), then freeze that selection with git commit into the repository. Staging is what lets you commit half your changes and keep the rest.
Click the commands to walk a change through
The file is edited but not yet staged.
Step 3 The object model — everything is content-addressed
Git stores four kinds of object, each named by the hash of its own content. A blob is a file's bytes; a tree is a directory listing (names → blobs/trees); a commit points at one top tree plus its parent commit(s) and metadata. Same content always produces the same hash — that is how Git deduplicates and verifies integrity.
Type some content — watch its object id
Change one character and the id changes completely; type the same text again and you get the same id. (Real Git prefixes a header and uses SHA-1/SHA-256; this is a stand-in hash for illustration.)
Step 4 History is a graph of commits
Each commit points back to its parent (a merge has two). Follow the arrows and you have the whole history — a directed acyclic graph. Git never edits a commit in place; "changing history" with rebase actually creates new commits and moves the branch pointer to them.
A small history
D is the tip; its parent is C, and so on back to the root A (which has no parent).Step 5 A branch is just a pointer
A branch like main is a tiny file containing one commit id — nothing more. HEAD says which branch you are on. Commit, and the current branch pointer simply slides forward to the new commit. Creating a branch is instant because it only writes 40 characters.
Commit and branch — watch the pointers move
HEAD → main → C. A commit moves the current branch forward; a new branch is just another pointer at the same commit.
Step 6 Glossary
| Term | In one sentence |
|---|---|
blob | The stored bytes of one file, named by their hash. |
tree | A directory listing: names pointing at blobs and sub-trees. |
commit | A snapshot: one top tree + parent(s) + author/message. |
staging area / index | The set of changes that the next commit will include. |
branch | A movable pointer to a commit (just a file with an id). |
HEAD | Which branch (or commit) you currently have checked out. |
DAG | The commit graph — each commit links back to its parent(s). |
merge vs rebase | Merge joins two histories with a new commit; rebase rewrites commits onto a new base. |
The whole idea: commits are content-addressed snapshots in a graph, and branches are just pointers into it. Almost every Git command is moving a pointer or adding an object — which is why it is so fast and so hard to actually lose work.