$ Git Game

I lost a commit

A commit you made is almost never gone. Every move of HEAD is written to the reflog, and a commit stays in the repository for weeks after nothing points at it. Three ways to lose one, and the way back from each.

A reset went too far

$ git reset --hard HEAD~1
HEAD is now at ab5768d api: the first endpoint
$ git log --oneline
ab5768d api: the first endpoint
07dec17 readme: the project
$ git reflog
ab5768d HEAD@{0}: reset: moving to HEAD~1
5a5bc93 HEAD@{1}: commit: auth: check the token
ab5768d HEAD@{2}: commit: api: the first endpoint
07dec17 HEAD@{3}: commit (initial): readme: the project
$ git reset --hard HEAD@{1}
HEAD is now at 5a5bc93 auth: check the token
$ git log --oneline
5a5bc93 auth: check the token
ab5768d api: the first endpoint
07dec17 readme: the project

git reflog lists where HEAD has been, newest first: the reset at HEAD@{0}, the commit it took away at HEAD@{1}. git reset --hard HEAD@{1} moves the branch back there. Some shells want the braces quoted.

A branch was deleted

$ git branch -D feature
Deleted branch feature (was 5a5bc93).
$ git reflog
ab5768d HEAD@{0}: checkout: moving from feature to main
5a5bc93 HEAD@{1}: commit: auth: check the token
ab5768d HEAD@{2}: checkout: moving from main to feature
ab5768d HEAD@{3}: commit: api: the first endpoint
07dec17 HEAD@{4}: commit (initial): readme: the project
$ git branch feature HEAD@{1}
$ git log --oneline feature
5a5bc93 auth: check the token
ab5768d api: the first endpoint
07dec17 readme: the project

git branch -D prints the hash it deleted, which is one way back: git branch feature and that hash. The reflog is the other: the commit sits at HEAD@{1}, under the checkout that left the branch, and git branch feature HEAD@{1} makes the branch again, pointing at it.

A rebase dropped it

$ git log --oneline
7a20dd4 api: add the endpoint
ab5768d api: the first endpoint
07dec17 readme: the project
$ git reflog
7a20dd4 HEAD@{0}: pull --rebase -X ours (finish): returning to refs/heads/main
7a20dd4 HEAD@{1}: pull --rebase -X ours (start): checkout 7a20dd4815012ed0c8bcd4fad2eae46182e82c61
a97e6d9 HEAD@{2}: commit: api: rename the endpoint
ab5768d HEAD@{3}: commit: api: the first endpoint
07dec17 HEAD@{4}: commit (initial): readme: the project
$ git reset --hard ORIG_HEAD
HEAD is now at a97e6d9 api: rename the endpoint
$ git log --oneline
a97e6d9 api: rename the endpoint
ab5768d api: the first endpoint
07dec17 readme: the project

A rebase that settles every clash in the other side's favour (the conflict page's -X ours) can leave your commit with nothing to apply, and drop it. The reflog shows the rebase's start and finish, and Git keeps the branch's tip from before any rebase, merge or reset in ORIG_HEAD, so git reset --hard ORIG_HEAD is the whole undo. A pull after a forced push can drop a commit the same way.

Undo the last commit, keep the work

$ git reset --soft HEAD~1
$ git status --short
A  auth.js

The most asked Git question has the smallest answer. --soft moves the branch back one commit and leaves everything that commit had, staged and ready to commit again. --hard throws the changes away as well, which is the first case above.

What the reflog can't bring back

The reflog is per clone: it records your HEAD, not the remote's, so it has nothing on a commit that only ever existed on someone else's machine. It holds commits, not uncommitted work: changes that were never committed are gone after git reset --hard. And its entries expire, after 90 days, or 30 for a commit nothing reaches any more.

Why the game does this to you

In Git Game nothing is lost either: every pack ever sent is in the game's log, and any game can be replayed day by day from it. On the table, the reflog card is the one you play after a push --force erased your commits: armed in your pack, it fires inside the forcer's pack and puts them back on top of main.

Play a day where this happens

One tap starts a game against the bot, and every day of it can be replayed afterwards.

play the bot now

Output captured from Git 2.50.1 (Apple Git-155) by scripts/git-output.sh, in a scratch repository with two clones, ana's and bot's, and fixed dates, so the hashes are the same on every run. It is captured again at every Git release.