you don't know git and you don't know it
A tour of Git features most developers never touch — interactive rebase, bisect, reflog, worktrees, fixup, and more — written to demo every construct in the MDX pipeline.
I've been using Git for over a decade — or so I thought. Turns out I was only using ~20% of what the tool actually offers. This post covers the good stuff: commands that live outside the add/commit/push loop.
If you've ever typed git commit -m "wip" more than once more than ten times on a daily basis, keep reading.
1. Interactive Rebase (rebase -i)
The single biggest productivity unlock. Instead of piling up "fix typo" commits, rewrite history before pushing.
# Squash the last 3 commits into one
git rebase -i HEAD~3
# The editor opens with a todo list:
# pick, reword, edit, squash, fixup, exec, break, dropPro tip: Combine with
git commit --fixupandgit rebase -i --autosquashfor zero-friction history rewriting. More on this in the fixup section below.
Each action in the rebase todo list maps to a function in Git's internal state machine. The formula for a clean history:
The interactivity comes from the GIT_SEQUENCE_EDITOR variable — set it to a script and automate the whole thing:
import { execSync } from "child_process";
type RebaseAction = "pick" | "reword" | "squash" | "fixup" | "drop";
function autoRebase(hashes: string[], actions: RebaseAction[]): void {
const script = hashes
.map((hash, i) => `${actions[i]} ${hash}`)
.join("\n");
execSync(
`GIT_SEQUENCE_EDITOR="echo '${script}' >" git rebase -i HEAD~${hashes.length}`,
);
}What each action does
| Action | Effect | When to use |
|---|---|---|
pick | Keep the commit as-is | Default for most commits |
reword | Keep changes, edit message | Fix a typo in the message |
squash | Combine into previous commit | Merge related changes |
fixup | Like squash, discard message | Minor fix, no new message needed |
drop | Remove the commit entirely | Something that shouldn't exist |
exec | Run a shell command | Run tests between steps |
2. Git Bisect — Binary Search for Bugs
When a bug appears and you have no idea which commit introduced it, git bisect performs a binary search over your history.
git bisect start
git bisect bad # current commit is broken
git bisect good v2.3.0 # this tag was working
# Git checks out the midpoint — test and mark:
git bisect good # midpoint is good → search upper half
git bisect bad # midpoint is bad → search lower half
# Repeat about log₂(n) times
git bisect reset # back to normal| Metric | Linear search | Bisect |
|---|---|---|
| Steps for 100 commits | 100 | |
| Steps for 1 000 commits | 1 000 | |
| Steps for a year (~250) | 250 |
The math is unbeatable — vs . You can even automate it:
git bisect start HEAD v2.3.0 --
git bisect run npm test # runs test at each midpoint
git bisect resetThe run subcommand expects a zero exit code (good) or non-zero (bad). This genuinely saves hours.
3. The Reflog — Your Safety Net
Think you lost work? You almost certainly haven't. The reflog records every HEAD movement for ~90 days.
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: implement oauth flow
# 123abcd HEAD@{2}: rebase -i (finish): returning to refs/heads/mainRecover a "lost" commit:
git checkout HEAD@{2}
# or cherry-pick it into your current branch:
git cherry-pick abc1234Reflog is local-only. It's not shared via
pushorfetch. Each clone has its own journal. The nameHEAD@{N}is a relative reference:Nsteps ago in the reflog.
Here's what you can recover from:
- Accidental
git reset --hard - Deleted branch (before GC)
- Aborted rebase aftermath
- Cherry-pick gone wrong
-
git push --forceon a shared branch — reflog won't save teammates - GC'd commits older than
gc.reflogExpire(default 90 days)
4. Git Worktrees — Parallel Development
Need to review a PR while keeping your working tree intact? git worktree lets you check out multiple branches simultaneously.
git worktree add ../hotfix hotfix/main
# Creates ../hotfix with hotfix/main checked out.
# Your current directory stays on feature/xyz.
git worktree list
# /Users/you/project (main)
# /Users/you/project/hotfix (hotfix/main)
git worktree remove ../hotfixWhen to use worktrees vs stashing
| Scenario | Worktree | Stash |
|---|---|---|
| Short context switch (< 5 min) | ✅ | |
| Long-lived parallel feature | ✅ | |
| Reviewing a PR mid-sprint | ✅ | |
| Quick hotfix on production | ✅ | |
| No disk space for another checkout | ✅ |
Gotchas:
- You cannot check out the same branch in two worktrees
- Detached HEAD in a worktree means manual cleanup
- Each worktree needs its own
node_modules— symlink if space is tight out of/Users/you/project
5. Fixup & Autosquash — History Editing on Autopilot
The --fixup / --autosquash combo is Git's most underrated feature.
import { execSync } from "child_process";
// Stage 1: make a fixup commit targeting a specific hash
execSync(`git commit --fixup ${targetHash}`);
// Git creates: "fixup! Original commit message"
// Stage 2: rebase with autosquash
execSync("git rebase -i --autosquash HEAD~10");
// The todo list arrives pre-sorted — fixup commits
// land right below their target. Just save and quit.Without --autosquash, you'd reorder manually in the editor:
# What you'd have to type:
pick abc1234 Add user auth
squash def5678 Fix typo in auth
pick 789abcd Add rate limiting
fixup 012def9 Oops, fix rate limitWith --autosquash, the todo list arrives already ordered. The GIT_SEQUENCE_EDITOR variable can script the entire pipeline — worth integrating into git-scm.com your editor of choice.
6. Advanced Logging
The plain git log is table stakes. Add --graph, --format, and path filters:
git log --graph --oneline --all --decorate --simplify-by-decorationThis shows a real picture of your branching topology. Pair it with --format for total control:
git log --graph --pretty=format:'%C(yellow)%h%Creset %C(cyan)%<(12)%an%Creset %s %Cgreen(%cr)%Creset' --allThe Math Behind Merge vs Rebase
A merge creates a three-way merge commit:
A rebase replays each commit from one branch onto another:
The end state is functionally identical, but the graph topology is very different. Neither is "right" — it's a social contract with your team.
A deeper look at the triangle
If a conflict arises, Git pauses and asks you to resolve it — one commit at a time. This is the edit phase of rebase, where $GIT_SEQUENCE_EDITOR meets $EDITOR and you stare at a terminal at 2 AM wondering why you didn't just merge.
Wrapping Up
Here's what to try this week:
- Run
git rebase -ion a feature branch - Recover a commit from
git reflog - Complete one
git bisectsession - Set up a
git worktreefor a PR review - Write a
--fixupscript for your editor - Customize
git logformat in~/.gitconfig
Further reading
| Resource | Why |
|---|---|
| Pro Git by Scott Chacon | The canonical reference, free online |
git help <command> | Every flag documented |
| git-scm.com | Searchable docs + videos |
This post demonstrates every construct in the MDX pipeline: headings (H1–H4), bold, italic, strikethrough, inline code, fenced code blocks with syntax highlighting (bash, TypeScript, YAML), line highlighting {1,4}, word highlighting /pattern/, line numbers, blockquotes, ordered and unordered lists, nested lists, GFM tables and task lists, inline and display math via KaTeX, autolinks <url>, reference links, and horizontal rules.
The best tool is the one you've already got — but actually know how to use.