A binary literally named git that, when run inside a jj (Jujutsu) repo,
refuses to actually run git and instead tells you to use jj.
AI coding agents (Claude Code, Cursor, et al.) keep running git inside
jj-managed repos despite being told to use jj. In a colocated jj+git
layout, that corrupts state. fuckgit shadows the real git on PATH
and traps these invocations, redirecting them with the equivalent jj
subcommand and inline jj help <subcmd> output.
It works on humans too, when they ask for it.
cargo install fuckgitThis installs a binary named git (yes, really) to ~/.cargo/bin/git.
Make sure ~/.cargo/bin is ahead of /usr/bin on PATH.
Linux and macOS only.
By default, fuckgit is a silent passthrough — every git invocation is
forwarded to the real git on PATH. The redirect only fires when
all of these are true:
- You're inside a jj worktree (a
.jjdirectory exists in the cwd or an ancestor — honoringgit -C <path>). - The intercept gate is open — at least one of:
FUCKGIT_INTERCEPT=1is set, OR- an AI-agent marker env var is set (currently just
CLAUDECODE).
- The subcommand isn't on the plumbing allowlist (
rev-parse,cat-file,for-each-ref, …). - None of the safety env vars are set:
GIT_DIR,GIT_EXEC_PATH,CARGO. - No top-level
--git-dir=or--work-tree=flag is present.
If any check fails, git behaves exactly as if fuckgit weren't installed.
When the redirect does fire, you'll see something like:
Don't use git. Use jj.
git status → jj st
jj has no staging area; `jj st` shows the working-copy commit's diff.
--- jj help status ---
Show high-level repo status [default alias: st]
…
Override with FUCKGIT_PASSTHROUGH=1 or git --fucking-git <args...>
…and exit 2.
When you need real git and the intercept is firing:
FUCKGIT_PASSTHROUGH=1 git <args>— env var overridegit --fucking-git <args>— flag override (the flag is stripped before exec'ing real git)
| Variable | Effect |
|---|---|
FUCKGIT_INTERCEPT=1 |
Open the intercept gate (opt in for your own jj repos). |
FUCKGIT_PASSTHROUGH=1 |
Force passthrough even with the gate open. |
CLAUDECODE |
Set by Claude Code; opens the gate automatically. |
To extend the AI-marker list, edit AI_MARKERS in src/main.rs and rebuild.
fuckgit knows the jj equivalent for these git subcommands:
status, log, commit, add, checkout, switch, restore, branch,
merge, rebase, pull, push, fetch, clone, init, diff, show,
reset, revert, cherry-pick, stash, tag, blame, remote,
bisect, config, reflog.
Unknown subcommands fall through to a generic "use jj instead" + jj help
output.
MIT — see LICENSE.