Do anything with git without looking it up. See what will happen first. Undo it after.
For interns, new grads, and anyone who still searches "how to undo last commit".
No AI, no account, no network: one binary that runs the real git.
- Say what you want.
gitwhy move my last commit to a new branchfinds the guided recipe and asks only what it needs (which commit? which branch?). - See it before it happens. gitwhy predicts the result with git's own dry runs: commits that leave a branch, files that change, and conflicts before they happen (for merge, rebase, cherry-pick, revert).
- Learn as you go. Every command it runs is shown and broken down part by part.
- Undo anything it ran. Before running, gitwhy saves branches, staged and unstaged changes, untracked files, stashes, and merge/rebase state.
gitwhy undoputs it all back, even afterreset --hardorclean -fdx. - Recover from plain git too.
gitwhy recoverreads git's history of your branch ("2h ago: pulled 14 commits from origin/master") and takes you back to before any of it. It also finds lost commits and staged files git still has. - Every git command and flag.
gitwhy buildwalks you through any command with every flag explained in a few words, from the docs in this repo (181 commands, ~3,500 flags, git 2.56).
curl -fsSL https://dpologdvinity.github.io/gitwhy/install.sh | sh # install (other ways below)
cd your-repo
gitwhy # full-screen home: changes, commits, branches, next steps
gitwhy undo last commit # say what you want; it asks only what it needs
gitwhy undo # changed your mind: put everything backYou need git 2.40 or newer. That is all: no account, no network, no setup.
Run gitwhy in a repo. A banner shows an operation in progress ("MERGE IN PROGRESS"), the status line shows
how far ahead or behind the remote you are, and Next: suggests what to do for the current state
(resolve conflicts, commit what's staged, push). Three tabs: Changes (with a live diff), Commits, Branches.
Keys act on the selected item and open the same guided recipe as the CLI, with the answers already filled
in: r reword a commit, d drop it, f add changes to it, s split it, m move it to a new branch.
Staging with space is instant, since it's always reversible. ? shows the keys for the current tab.
enter on a changed file shows its hunks: space stages one, v picks single lines.
Commits tab draws the branch graph; a shows all branches, p copies a commit here.
gitwhy |
Full-screen home: changes, commits, branches, and the next step for your repo's state |
gitwhy menu |
Simple menu |
gitwhy <words> |
Search, e.g. gitwhy squash commits |
gitwhy do [recipe] |
Run a guided recipe by name (no name: list them) |
gitwhy run <git command> |
Preview, explain, run with undo: gitwhy run git rebase main |
gitwhy explain <git command> |
Explain each part without running it |
gitwhy build [command] |
Build any git command from its flags |
gitwhy undo [--list] |
Undo the last gitwhy action (or pick one) |
gitwhy recover |
What happened recently, and go back |
gitwhy resolve / continue / abort |
Fix conflicts, then continue or cancel a merge/rebase |
-q / GITWHY_EXPLAIN=0 hides the breakdown. ACCESSIBLE=1 uses plain-text prompts (screen readers, scripts).
Undo last commit (keep staged / unstaged / delete) · undo a pushed commit safely · change a commit message (any commit) · remove a commit · reorder, squash, fixup, rename or drop recent commits · squash last commits · split a commit in two · add changes to an older commit · move commits to a new or existing branch · copy a commit from another branch · make a branch the same as master · make a branch exactly match the remote · create, switch, rename, delete branches (local and remote) · merge · update my branch from master (rebase or merge) · resolve conflicts, continue, abort · push (normal / safe force / force) · pull · stash and restore · discard, stage, unstage files · delete untracked files · fix a commit's author · tags: create, delete, push · remotes: add, change URL, set upstream · stop tracking a file but keep it · rename a file · get an old version of a file back · Git LFS: track, migrate, pull, list · remove a file from all history · worktrees · sparse checkout on/off · submodules · find a commit by message or code · find which commit broke something (bisect) · history, file history, compare branches, blame, see my changes.
gitwhy do lists them all. Each is a small YAML file in recipes/; add your own.
Needs git 2.40+. Tested on Linux, WSL and Windows (CI). macOS installs and runs in CI but has not been used on a real Mac.
curl -fsSL https://dpologdvinity.github.io/gitwhy/install.sh | shThis downloads the latest release, checks its
checksum, and puts gitwhy in ~/.local/bin. Or with Homebrew:
brew install dpologdvinity/gitwhy/gitwhyThe package needs git 2.40 or newer (Debian 13 or Ubuntu 24.04 and later); older releases can add the
repository but apt will refuse the install.
sudo install -d -m 0755 /etc/apt/keyrings
sudo curl -fsSL https://dpologdvinity.github.io/gitwhy/gitwhy.asc -o /etc/apt/keyrings/gitwhy.asc
echo "deb [signed-by=/etc/apt/keyrings/gitwhy.asc] https://dpologdvinity.github.io/gitwhy/apt ./" | sudo tee /etc/apt/sources.list.d/gitwhy.list
sudo apt update && sudo apt install gitwhyThe package needs git 2.40 or newer (Fedora 39 and later).
sudo curl -fsSL https://dpologdvinity.github.io/gitwhy/gitwhy.repo -o /etc/yum.repos.d/gitwhy.repo
sudo dnf install gitwhyEach release also has .deb, .rpm, .apk (Alpine) and .pkg.tar.zst (Arch) files you can install directly.
With Scoop:
scoop bucket add gitwhy https://github.com/dpologdvinity/homebrew-gitwhy
scoop install gitwhyOr with PowerShell (no Scoop needed):
irm https://dpologdvinity.github.io/gitwhy/install.ps1 | iexOr download the zip from the releases page.
npm i -g @kaitlynbassford/gitwhy # or: bun add -g @kaitlynbassford/gitwhy
npx @kaitlynbassford/gitwhy # to try it onceThe command is still gitwhy. The binary is downloaded from the release and checked against its
checksum, at install or on first run.
nix --extra-experimental-features 'nix-command flakes' run github:dpologdvinity/gitwhy
nix --extra-experimental-features 'nix-command flakes' profile add github:dpologdvinity/gitwhy(Leave out the --extra-experimental-features part if flakes are already enabled in your Nix config.)
This builds from source, so gitwhy version shows the commit instead of a version number.
git clone https://github.com/dpologdvinity/gitwhy && cd gitwhy
go build -o ~/.local/bin/gitwhy ./cmd/gitwhy(go install ...@latest doesn't work: go.mod replaces a clipboard library with a copy that
doesn't slow startup on WSL, and go install refuses modules with replace directives.)
Snapshots live in .git/gitwhy/ (last 20). The working-tree copy is a normal git commit kept alive by
refs/gitwhy/snapshots/<id>, so it costs little space. Ignored files are not saved, except files a
command is about to delete (gitwhy asks git's dry run which ones). Anything already sent to a remote
(push) can't be undone locally.
git push --mirror would also push refs/gitwhy/*; gitwhy warns when it runs one. After removing a
leaked secret from history, the old commits stay in your local undo points until they're pruned
(delete .git/gitwhy and git update-ref -d the refs/gitwhy/* refs to drop them sooner).
Undo leaves alone any branch that changed after the action (for example a commit you made later in plain git, or work in another worktree), and tells you which.
gitwhy hook installThis wraps git in your shell so gitwhy undo works for commands you type yourself. It snapshots
before risky commands only (like reset --hard, checkout <file> or clean -fd), costs a few ms on
other commands, and works in bash and zsh. Set GITWHY_HOOK_OFF=1 to pause it; gitwhy hook uninstall
removes it.
It sees through global options (git -C dir ..., git -c k=v ..., git --no-pager ...) and simple
aliases (alias.rh = reset --hard). It does not cover --git-dir or --work-tree (it cannot tell
which repository you mean), shell aliases (starting with !), or git run by other programs.
gitwhy is one Go binary that runs the real git. Every change goes through the same pipeline:
- Plan: a recipe (a goal such as "undo last commit") or a literal command becomes concrete git commands.
- Show: gitwhy previews the result with git's dry runs, warns about danger, and explains each part.
- Save: after you confirm, it takes a snapshot of branches, files, index, stashes and state.
- Run: it runs the git commands, then records what changed so
gitwhy undocan reverse exactly that.
The engine (internal/snapshot, preview, danger, recipe, explain) has no user interface; internal/ui
(prompts) and internal/tui (full screen) sit on top. ARCHITECTURE.md has the diagrams,
the data on disk and the design decisions.
go test ./... # unit + end-to-end tests (real git, temp repos)
golangci-lint run ./... # must report "0 issues."
python3 scripts/check_coverage.py # every flag in your git's -h/man pages is documented
python3 scripts/build_index.py # rebuild docs/README.mdCONTRIBUTING.md explains the workflow, the CI checks every pull request must pass, and how to add a recipe, a warning or a command doc. Docs are original plain-English descriptions (git's own docs are GPL-2.0; nothing is copied). Format: docs/STYLE.md. Report security problems privately through the repository's Security tab.
MIT. third_party/clipboard is BSD-3-Clause (github.com/atotto/clipboard, changed to detect tools lazily).
