Skip to main content

git-game

Learn git by playing. You work in your own terminal with real git commands on a real remote repository, while the game shows the rules of the current level next to it. Rules appear one at a time and are re-checked every second, so a green rule can turn red again. A Gremlin works on the same repository and breaks things along the way: you fix them with git.

Level You learn The Gremlin...
0 · Foundations branch, commit, push, merge requests, conflicts just watches
1 · Cherry-pick cherry-pick, ranges, reset commits R8 on your R6 branch, moves your branch after the push, publishes docs with a debug print hidden among them
2 · Interactive rebase reword, fixup, drop, autosquash, force-with-lease "implements" R9 in 6 messy commits, adds a fixup!, pushes on your branch right before your force-push
3 · Reflog reflog, ORIG_HEAD runs reset --hard, deletes a branch, drops a commit with a rebase
4 · The leak rotation, git filter-repo, cleaning remote refs spreads a token across files, messages, a tag and a backup branch

Contributions are welcome: new levels, new tricks for the Gremlin, better hints, bug fixes.

Play

pipx install git-game        # or: uv tool install git-game
git-game
  1. On your git server create a new, empty, private repository (without a README).
  2. Start the game and paste the repository's SSH URL. The game clones it into ./play (change it with --play).
  3. Keep the game open next to a normal terminal and follow the rules.
Key Action
h hint for the newest red rule; inside the hint, hold s to reveal the solution
b the level's board: where you are, what's done, where the Gremlin strikes
t switch the history panel between your clone and origin
p panic: undoes the Gremlin's last trick on your local branches
q quit; your progress is saved in ~/.gitgame

git-game --new forgets the saved game and starts over. Level 4 needs git filter-repo (pipx install git-filter-repo).

Development setup

You need Python 3.12+, git and uv.

git clone https://git-softeng.polito.it/s331551/git-edu.git
cd git-edu
uv sync                       # creates .venv with the game and the dev tools (pytest, git-filter-repo)
uv run git-game               # play your working copy
uv run pytest                 # run the tests

Project layout

Path What it holds
gitgame/levels.py the levels: every rule with its text, hint, solution, check and Gremlin trick
gitgame/engine.py the game state, the loop that runs checks and tricks, the git hooks installed in the player's clone
gitgame/git.py small helpers around the git command line
gitgame/app.py the terminal UI (Textual)
gitgame/board.py the level board and the track drawn with text
gitgame/baseline/ the starting code the game pushes to the player's empty repository
tests/test_playthrough.py plays the whole game against a local bare repository
tests/test_app.py UI tests

How the game works

  • Watching the player's clone. Every second the engine reads the clone. It also installs hooks in .git/hooks (post-commit, post-checkout, post-merge, post-rewrite, pre-push) so it reacts right away and the Gremlin's messages show up in the player's terminal. It never overwrites the player's own hooks.
  • Reading the remote. The game keeps a private clone in ~/.gitgame/gremlin-clone, used to read the remote and to push the Gremlin's commits with the player's SSH key.
  • Safety. The Gremlin acts only on the clone whose origin is the game's repository. It waits while the working tree has uncommitted changes or an operation is in progress, saves the position of the branches before every trick, and never force-pushes main.
  • Secrets. Level 4 never asks for a password: it asks for a throw-away access token, or a fake one.

Adding or changing a rule

A level is a Level(name, intro, rules) in gitgame/levels.py, and LEVELS lists them in order. Each rule is:

Rule(title, text, hint, solution, check, trick=None, latch=False)
  • text, hint and solution are Markdown, or functions f(engine) that return it (useful to show real commit hashes).
  • check(engine) returns None when the rule is satisfied, otherwise a short message telling the player what is still missing.
  • trick(engine) is the Gremlin's move, run once when the rule unlocks. It returns the message shown to the player. Raise Wait("...") when the repository isn't in the state the trick needs yet.
  • latch=True keeps the rule green once it has been satisfied, for rules about recovering something that later rules change again.

Store what a trick creates (hashes, names) in engine.data and call engine.save(), so checks and hints can find it after a restart.

Every rule and every trick must be covered by tests/test_playthrough.py: the scripted player has to turn the rule red with the trick and green again with the solution you give in solution.

Contributing

  1. Open an issue first for a new level or a big change, so we can agree on it.
  2. Create a branch, make your change, add or update the playthrough test.
  3. Run uv run pytest and make sure it passes.
  4. Open a merge request. The pipeline (.gitlab-ci.yml) runs the tests on every merge request and on main.

Releasing

Releases go to PyPI through the CI pipeline (.gitlab-ci.yml):

uv version --bump minor       # or patch / major: updates pyproject.toml
git commit -am "Release v$(uv version --short)"
git tag "v$(uv version --short)"
git push && git push --tags

Pushing a v* tag runs the tests, checks that the tag matches the version in pyproject.toml, builds the package and publishes it with the PyPI API token stored in the PYPI_TOKEN CI/CD variable (masked and protected, only maintainers can see it).

License

Released under the GNU General Public License v3.0 or later.

Metadata

Release files for git-game 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for git-game 0.1.0
File Size Uploaded
git_game-0.1.0.tar.gz 53.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for git-game 0.1.0
File Interpreter ABI Platform
git_game-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 107.6 kB

Release files / git_game-0.1.0.tar.gz

Download URL git_game-0.1.0.tar.gz
Size 53.8 kB
Tags Source
SHA-256 checksum
How to use checksums
12070871290eb00e5b2e1fb3b6e627e4b80650fec8121bb65da11c591d6e9eaf
BLAKE2b-256 checksum
How to use checksums
8158fb51b428692b1441b710cc1f4b19a876f36fbbbd886199e70d40a4dfecd3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_game-0.1.0-py3-none-any.whl

Download URL git_game-0.1.0-py3-none-any.whl
Size 53.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d23e813f8d5fae6f6f55f4584c5edbb798869a3bf32d4d626ef33f3662bc81c0
BLAKE2b-256 checksum
How to use checksums
c1835f6cf2ea5082357829f7c4ebb5330eb5f8191170268acb3804c20ce8d150
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page