Skip to content

Repository files navigation

learngit: learn Git by moving the graph

Type real Git commands into a repository that does not exist, and watch the commit graph move.

Open it  ·  The basics  ·  All 33 levels  ·  Cheat sheet  ·  Sandbox


Next.js React TypeScript Tests Runtime deps Licence


Why this exists

Most people learn Git by memorising four commands and then being frightened of the fifth. That is not a knowledge problem, it is a feedback problem. git rebase is genuinely simple once you have watched it happen; it is impossible to reason about from prose.

The thing that reliably teaches Git is seeing the graph change under your own commands. That normally needs a repository you are not afraid to break, which needs setup, which is where most people quit.

So there is no setup. The repository is simulated, the commands are real, and nothing here can touch anything on your machine.


The idea in one picture

Working tree, staging area, history

What the screen looks like

Level 4.1, Merge versus rebase: the working directory and editor on the left, the commit graph in the centre showing main, merge-way and rebase-way diverging from one commit, and the lesson panel on the right.

Three panels and a prompt. The graph is the biggest thing on screen at all times, because the graph is the lesson and the text is the footnote. Nothing there is a mockup: that is a real level, mid-solve, with a real repository behind it.


The curriculum

# Chapter What you walk out with Levels
01 Commits Files, staging, commits, and reading history 3
02 Branches A branch is a pointer. Everything else follows 4
03 Merge Fast-forward, real merges, and what a second parent means 4
04 Rebase Replaying commits onto a new base, and --onto 5
05 Conflicts Markers, --continue, --abort, ours versus theirs 4
06 Remotes Fetch, pull, push, and why a push gets rejected 5
07 Undo reset, revert, reflog, and which of them rewrite history 5
08 Boss level No new commands. Real scenarios, start to finish 3

Chapter 4 gets the most minutes because rebase is the reason this exists. Chapter 8 adds no new commands at all, because retrieval practice is what actually moves knowledge into long-term memory.


What is actually simulated

This is a teaching simulator, not a Git implementation. It models behaviour, not plumbing: there is no zlib, no packfile, no index format. What it does model, it models properly.

lib/engine/
  state.ts        the three trees, refs, reflog, stash, snapshot/restore
  refs.ts         HEAD~2, HEAD^2, origin/main, HEAD@{n}, stash@{n}, hash prefixes
  diff3.ts        a real LCS three-way merge, with conflict markers
  sequencer.ts    one implementation driving every paused operation
  commands.ts     the command surface
  parse.ts        tokeniser and dispatch
lib/graph/
  layout.ts       topological sort into lanes and rows
  render.ts       SVG built imperatively, animated by diffing layouts

Three decisions are worth calling out:

Commits store whole trees, not deltas. A commit is a full snapshot. This makes applyPatch, checkoutTree and mergeBase a few lines each, and it is also how Git itself thinks about commits, so the model the learner builds is the correct one.

One sequencer for every paused operation. Rebase, merge, cherry-pick and revert all pause the same way and resume through the same code, so --continue, --abort and --skip behave identically everywhere. That is the behaviour that transfers to a real terminal.

Goals match on structure and messages, never on hashes. They cannot match on hashes: after a rebase the hashes are supposed to be different. Goal checking is graph isomorphism over commit messages, with a predicate escape hatch for the handful of levels where messages repeat.


The animation is not scripted

No command carries hand-written animation. The renderer keeps the previous layout in memory and diffs it against the new one, which leaves exactly three cases:

Case What you see
A node that moved it slides
A node that is a copy of an older node it lifts off the original and flies to its new base
A genuinely new node it pops in

That third case is why a rebase reads correctly the very first time you run one. Nobody choreographed it. It falls out of the data.


Running it

bun install
bun dev            # http://localhost:3000
bun test           # 130 tests, engine plus every level
bun run lint
bun run build      # 146 static pages, no server needed

Set NEXT_PUBLIC_SITE_URL at build time so shared links resolve absolute preview images.


Tests

Two things are tested, because two things can break silently.

The engine, against real Git semantics: fast-forward versus true merge, rebase copying rather than moving, all three reset modes, conflict markers and resolution, --force-with-lease refusing when the lease is stale.

Every level, end to end. Each one is built from its setup, its own published solution is run through the parser, and the goal checker must pass. This has already caught two authoring bugs that would have been invisible in review: a level that completed the moment it loaded, and a level that could never be completed at all.

bun test
 130 pass
 0 fail

Contributing

Levels live in lib/levels/ and are plain TypeScript, one object per level:

{
  id: '4.3',
  title: 'Transplant a branch',
  brief: 'hotfix was cut from feature by mistake...',
  setup: { commits: [...], branches: {...}, head: {...} },
  steps: [{ t: 'Put hotfix on top of main', f: () => ... }],
  goal:  { commits: [...], branches: {...} },
  hints: ['...', '...', '...'],
  solution: ['git rebase --onto main feature hotfix'],
  teach: 'Three arguments: where it lands, where to cut, what to move.',
}

Add one, run bun test, and the suite will tell you whether your own solution actually solves it.

Issues and pull requests are welcome. If you are adding a command, add the level that teaches it in the same change: a command with no level is a command nobody will discover.


Licence

MIT. Do what you like with it.


Built with love by vanshcodeworks

learngit.vanshcodeworks.com  ·  vanshcodeworks.com  ·  GitHub  ·  LinkedIn

A simulator, not a Git implementation. It teaches behaviour, not plumbing.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages