lazygit is the git TUI used here (installed via the lazyvim_deps role; bound to lg). The everyday stuff (stage, commit, branch) is obvious — this page is the rebase/amend "surgery" that's hard to remember, with the lazygit keys and the equivalent CLI side by side so you can do it either way.
Golden rule: only rewrite commits that have NOT been pushed. All recipes below rewrite history (new SHAs). If a commit is already on a shared remote, don't — or you'll need
git push --force-with-leaseand coordination.
This dotfiles repo sets Git's global baseline to:
[pull]
rebase = true
[rebase]
autoStash = trueSo LazyGit's normal p pull runs as a rebase pull, and dirty working-tree changes are stashed before the rebase and re-applied afterwards. If the re-applied stash conflicts, Git keeps the autostash instead of dropping it; inspect git status and git stash list, resolve any worktree conflicts, then drop the autostash only after confirming your changes are back.
The word fixup shows up in two unrelated lazygit operations — confusing them is the #1 way to mangle history:
| Goal | lazygit | What it does |
|---|---|---|
| Add working-tree changes into an existing commit | A (Commits panel) = amend commit with staged changes |
Runs git commit --fixup + git rebase --autosquash under the hood |
| Merge two existing commits into one | f / c (Commits panel) = fixup / squash |
Squashes the selected commit into the one below it (older) |
So A = "put my edits into that old commit"; f = "glue these two commits together". Reaching for f to add a file will mash neighbouring commits instead.
Read-only lookup — no history rewrite, safe even on pushed commits.
lazygit
<ctrl+s>(global) → View options for filtering the commit log → enter the path. The Commits panel now lists only commits that touched it;<enter>on any commit drills into that file's diff.<ctrl+s>again to clear the filter.
lazygit's filter doesn't follow renames and makes you open commits one at a time — for real file-history browsing a dedicated tool is nicer:
CLI
tig path/to/file # best: log scoped to the file, <enter> opens each commit's diff, follows renames
git log --follow -p -- path/to/file # follow renames + full diff each time (piped through delta here)
git log --follow --oneline -- path/to/file # quick "which commits touched it"lazygit
- Files panel: press
<space>on only the file you want. Do not pressa— that's stage all and will sweep unrelated edits into the amend. - Commits panel: select the target commit →
A.
CLI
git add path/to/file
git commit --fixup=<target-sha>
git rebase --autosquash --autostash <target-sha>~1
# non-interactive (skip the editor): prefix with GIT_SEQUENCE_EDITOR=trueThe inverse — un-commit a single file from an unpushed commit into "not staged" changes. lazygit's custom patch is the native tool.
lazygit
- Commits panel: select the commit →
<enter>to view its files. - Highlight the file →
<space>(adds the whole file to the custom patch — it gets marked). <ctrl+p>→ View custom patch options →move patch out into index. This rewrites the commit without the file and stages the change.- Files panel:
<space>on the file to unstage it → now it's a Changes not staged edit.
In the patch menu,
move patch out into indexis what you want.remove patch from original commitdiscards the change (lost) — don't pick that if you want to keep it.
CLI
git rebase -i <sha>~1 # mark <sha> as 'edit', save & quit
git reset HEAD^ -- path/to/file # un-commit just that file -> working-tree change
git commit --amend --no-edit # re-make the commit without it
git rebase --continueYou edited a file but want to keep those edits as a separate new file while resetting the original back to HEAD (e.g. spin an experiment off into a copy). No single keybinding, but two quick steps: the copy captures the modified content, then discard restores the original.
lazygit
:(Execute shell command) →cp path/to/file path/to/file.new— the copy grabs the current, modified content. The:shell runs at the repo root.- Files panel: select the original →
d→ discard → restored toHEAD. - Edit
path/to/file.newfrom there.
CLI
cp path/to/file path/to/file.new # modified content -> new file
git restore path/to/file # original back to HEAD (git checkout -- <file> on older git)Want to re-apply the change later rather than fork it?
git stashsaves the edit and restores the original in one step — but it lands in the stash list, not a new file.
lazygit — z undo / Z redo (works on branch/commit ops; the worktree must be clean). For deeper recovery use the reflog via CLI:
CLI
git reflog # find the good SHA from before the mess (e.g. the original HEAD)
git reset --hard <good-sha> # restore branch + worktree to that point- Gotcha:
git reset --harddeletes files that were staged as new adds (e.g. a freshlygit added plan file) — back them up first. It leaves plain untracked files alone. - Re-apply any uncommitted WIP you want to keep afterwards (e.g.
git diff > /tmp/wip.patchbefore,git apply /tmp/wip.patchafter).
a= stage ALL in lazygit. It silently sweeps unrelated edits (e.g. a transient config tweak) into whatever amend/fixup you do next. Stage one file with<space>.- After any of these, the commit's SHA changes. Fine for local commits; push normally (force only if it was already pushed).
- Commit discipline when files are partially staged:
git resetto clear the index, thengit addexactly what you mean beforegit commit.
- git diff workflow
- Per-tool tips/recipes live under
docs/tools/<tool>.md— this page is the home for git/lazygit recipes.