skipnothing/Git
UNIT 04

Rewriting & Undoing

Amend, rebase, reset, bisect, and recovery

Git never truly deletes anything. Even when you rewrite history, the old commits are still there, recovery is always possible.

Loading…
BUILDS ON
TOPICS
#11

Amend & Fixup

Correct the tip of your branch with `git commit --amend`, which writes a new commit and moves the ref while the original waits in the reflog, then queue a fix for a buried commit by writing a `fixup!` marker to fold in later.

You just committed `Add config.json`, then spot a typo in the message and reach to fix it in place. Git has no such button: change one byte and `git cat-file -p` prints a different object with a different name.

10 min
#12

Rebase

Rebuild your branch's commits onto a new base, watching each become a new object with the same diff but a fresh parent and hash, fold a queued `fixup!` marker into its target with `--autosquash`, and see why `ours` and `theirs` swap when a replay hits a conflict.

Your feature branch holds three commits, and `main` has moved ahead since you branched off it. You want your three sitting on top of today's `main`, carrying the same file changes on fresh footing.

15 min
#13

Reset, Revert & Clean

Rewind a branch with `git reset` and pick with `--soft`, `--mixed`, or `--hard` how far the staging area and working tree follow; append a push-safe inverse commit with `git revert` (choosing a mainline with `-m` on a merge); and wipe untracked files with `git clean -fd`, the only one of the three the reflog cannot undo.

You ran `git reset` once and lost an afternoon of edits, then ran almost the same command another day and nothing bad happened at all. Undo in git is really three separate tools wearing one word.

12 min
#14

Cherry-pick

Copy the change from any commit onto your current branch as a new object with its own hash while the original stays put, select a merge's mainline with `-m`, and run a range through the sequencer that halts on a conflict with four ways out.

A one-line fix lands on `main` as commit `a1b2c3d`, but the same bug is still live on `release/v2.5`. Merging the whole branch drags along ten unrelated commits; you want that single change and nothing else.

12 min
#15

Bisect

Pinpoint the commit that broke a test by halving a 1024-commit range in about ten classifications, read the `.git/BISECT_*` state the search parks on disk without moving your branch, and automate the whole loop with `git bisect run` (exit 0 good, 125 skip, non-zero bad).

A test passed at tag `v1.0` and fails on the newest commit, 1024 commits later. Testing them one at a time means 1024 runs; there is a way to name the culprit in ten.

12 min
All units