Reason through git workflow problems and surface the right advanced git command. Each section maps a real situation to a specific tool with concrete commands to run.
Invoke this skill when the user:
- Needs to find when or where a bug was introduced
- Needs to work on more than one branch at the same time
- Suspects a secret, credential, or sensitive string exists somewhere in history
- Keeps resolving the same merge conflict and wants it to stop
- Wants to verify that a rebase or cherry-pick didn't silently alter any patches
- Is in a large monorepo and only cares about a subset of files
- Wants to attach metadata (ticket number, deploy info, test result) to a commit without rewriting history
- Made a small mistake in a past commit and wants to fix it cleanly
- Needs to understand who originally wrote code that was later moved to another file
- Has no network access but needs to move a git repo to another machine
Also trigger when the user describes any of these in natural language without naming the command — e.g. "how do I find which commit broke this?", "can I have two branches open at once?", "how do I track down when a token got committed?".
Work through these in order. Ask the first diagnostic question, then follow the branch.
Ask: Do you know approximately when the bug appeared — a tag, a date, a deploy?
Yes — known good ref exists:
git bisect start
git bisect bad HEAD
git bisect good <known-good-tag-or-sha>
# If you have a test that catches it:
git bisect run <your-test-command>
# Otherwise step through manually with: git bisect good / git bisect bad
git bisect resetgit bisect run is strongly preferred — it drives itself to the culprit with ⌈log₂(N)⌉ runs.
No — no known-good ref:
First use the pickaxe (section 3) to find when the relevant code changed, then use that commit as the git bisect good anchor.
Ask: Do you need two (or more) working trees active at the same time — e.g. an AI agent on a feature branch while you review a hotfix?
Yes:
git worktree add ../<directory-name> <branch-name>
git worktree list # see all active worktrees
git worktree remove ../<directory-name> # clean up when doneEach worktree shares the same .git — no second clone, no wasted disk on object storage.
No — just want to switch branches cleanly without losing context:
git stash push -u -m "wip: <description>" then git stash pop on return. But if this happens often, switch to worktrees anyway.
Ask: Do you know the exact string (or a close literal) that you're looking for?
Yes — looking for exact text (e.g. a credential value):
git log -S "<exact-string>" --all --oneline
git log -S "<exact-string>" -p --all # show full diff for each hitFinds every commit where the count of that string in a file changed (added or deleted). Works even if the file has since been deleted.
Yes — looking for a pattern (e.g. all assignments to a variable):
git log -G "<regex>" --all --onelineNo — looking for when a function or feature was changed:
git log -L :<function-name>:<file> # traces a function through historySecurity note: finding it with -S means it's in history. Even after deletion from HEAD, rotate any credential you find.
Ask: Has this same conflict (same lines, same files) come up before — on a rebase, a re-merge, or a retry?
Yes:
# Enable once, globally:
git config --global rerere.enabled true
# From now on: resolve conflicts normally.
# rerere records the resolution fingerprint automatically.
# Next time the same conflict appears, it applies the fix without prompting.
# Inspect recorded resolutions:
ls .git/rr-cache/No — first time seeing this conflict: resolve normally. If you enable rerere now, it will record this resolution for future use.
Ask: Did you just rebase a branch (or cherry-pick a range) and want to confirm no patch changed content?
Yes:
# Compare the before and after sequences patch-by-patch:
git range-diff <base>@{1} <base> <branch>
# Or compare two parallel sequences from a common ancestor:
git range-diff <ancestor>..<branch-a> <ancestor>..<branch-b>= means patches are equivalent. ! means something changed — the inner diff-of-diffs shows exactly what.
Ask: Do you only need a subset of the repo's directories?
Yes — already cloned:
git sparse-checkout init --cone
git sparse-checkout set <dir1> <dir2>
git sparse-checkout list # see what's included
git sparse-checkout disable # restore everythingYes — haven't cloned yet:
git clone --filter=blob:none --sparse <url> <local-dir>
cd <local-dir>
git sparse-checkout set <dir1> <dir2>Objects for excluded paths are not fetched — minimal disk and network use.
Ask: Do you need to record something about a commit (deploy timestamp, ticket ref, test result, reviewer note) after the fact?
Yes:
git notes add -m "<your note>" <commit-sha-or-ref>
git notes show <commit-sha-or-ref>
git log --show-notes --oneline
# Notes don't push automatically:
git push origin refs/notes/commits
git fetch origin refs/notes/commitsNote: notes are not visible on GitHub's UI by default. Best for internal tooling, CI annotation, and audit trails — not for end-user-facing metadata.
Ask: Is the mistake in the most recent commit (HEAD)?
Yes — HEAD only:
git add <fix>
git commit --amend --no-editNo — further back:
# Stage the fix, target the specific commit:
TARGET=$(git log --grep "<part of original message>" --format="%H" | head -1)
git add <fix>
git commit --fixup "$TARGET"
# Squash it in automatically:
git rebase -i --autosquash <branch-base>Enable globally so you never need to type --autosquash:
git config --global rebase.autoSquash trueAsk: Does git blame on the current file point to a refactor commit rather than the commit that wrote the logic?
Yes — code was moved or copied:
git blame -C -C -C <file>Three -C flags detect copies across commits and across files. Lines are attributed to the commit that wrote the logic, not the commit that moved it.
No — blame is accurate: no action needed.
Ask: Do you need to transfer a git repo to a machine with no internet access, or create an offline backup?
Full transfer:
git bundle create repo.bundle --all
git bundle verify repo.bundle # confirm self-contained
# copy the file (USB, SCP, email, etc.)
git clone repo.bundle <destination>Delta only (already partially synced):
git bundle create delta.bundle main ^<last-synced-ref>
# on the other side:
git fetch delta.bundle main:main| Situation | Command |
|---|---|
| Find which commit introduced a bug | git bisect run <test> |
| Two branches open simultaneously | git worktree add |
| Find when a string appeared/disappeared in history | git log -S "<string>" |
| Stop resolving the same conflict repeatedly | git config --global rerere.enabled true |
| Verify rebase/cherry-pick didn't alter patches | git range-diff |
| Work in a subset of a monorepo | git sparse-checkout set <dirs> |
| Annotate a commit without changing its SHA | git notes add |
| Fix a past commit without painful interactive rebase | git commit --fixup + --autosquash |
| Blame that survives a refactor | git blame -C -C -C |
| Move a repo without a network | git bundle create |
Every scenario above has a working exercise in this repo:
bash setup.sh # build the demo repo with crafted history
cd demo-repo
# then open exercises/01-worktree.md through exercises/10-bundle.md