Git DAG Simulator
Build a commit graph with four git commands and watch what each one does to it. Every commit, every ref move and every parent edge is drawn as it happens.
A worked example, rendered when the site was built. No JavaScript required. It is the scenario called A true merge: Both branches moved, on different files, so the merge makes a commit with two parents. With JavaScript on, this is replaced by the same engine with a command builder attached, so you can run these commands yourself and start from any of the five scenarios.
| Step | Command | Result | What happened |
|---|---|---|---|
| 1 | git commit -m "Add the readme" (README.md) | ok | Commit 194fc6e records a change to README.md on main, and it is a root commit, so it has no parent. |
| 2 | git commit -m "Expand the readme" (README.md) | ok | Commit 90031ec records a change to README.md on main, and its parent is 194fc6e. |
| 3 | git branch feature | ok | feature now points at 90031ec. HEAD did not move, so you are still where you were. |
| 4 | git checkout feature | ok | HEAD is attached to feature, which points at 90031ec. |
| 5 | git commit -m "Write the feature" (src/main.rs) | ok | Commit 4f960b4 records a change to src/main.rs on feature, and its parent is 90031ec. |
| 6 | git checkout main | ok | HEAD is attached to main, which points at 90031ec. |
| 7 | git commit -m "Jot down the plan" (notes.txt) | ok | Commit 14098f1 records a change to notes.txt on main, and its parent is 90031ec. |
| 8 | git merge feature | merge | A merge commit 9d3ba49 joins both histories. Its first parent is 14098f1, where HEAD was, and its second is 4f960b4, the tip of feature. |
| Ref | Points at | Commit |
|---|---|---|
| HEAD | main | 9d3ba49 |
| feature | 4f960b4 | 4f960b4 |
| main | 9d3ba49 | 9d3ba49 |
| Commit | Refs here | Message | Parents | File |
|---|---|---|---|---|
| 9d3ba49 | HEAD, main | Merge branch 'feature' | 14098f1, 4f960b4 | none, a merge changes nothing itself |
| 14098f1 | none | Jot down the plan | 90031ec | notes.txt |
| 4f960b4 | feature | Write the feature | 90031ec | src/main.rs |
| 90031ec | none | Expand the readme | 194fc6e | README.md |
| 194fc6e | none | Add the readme | none, this is the root commit | README.md |
The ids here are synthetic, drawn from a seeded generator rather than hashed. If you want the real function, the Hash Generator runs SHA-1 and its successors over your own input, and Hashprint turns a digest into a picture you can compare at a glance.
About this lab3 paragraphs
Four commands, and nothing else: commit, branch, checkout (including a detached HEAD) and merge, in both of its shapes. A fast-forward moves a ref along a chain that already exists and makes no commit; a true merge makes one commit with two parents, and the drawing shows both edges. Commands are built from pickers rather than typed at a fake shell prompt, so every argument is a real choice from the repository in front of you.
Nothing here is random and nothing reads a clock. Commit ids are synthetic: seven hex characters from the site's seeded generator, not a real SHA-1, because teaching the graph does not need the hash function and a seeded id makes the whole repository reproducible. Pick a scenario, replay its commands, and you get the same ids every time, on any machine.
What it does not do is the rest of git. rebase -i, cherry-pick, reset, revert, stash, reflog and anything to do with remotes are recorded as deferred, and a merge that collides is marked rather than resolved: the lab shows you that a conflict happened and on which file, and it stops there. There is no diff editor.