Rebase, Interactive Rebase, Cherry-Pick, Amend, and Safe History Editing: Guided Hands-On Workflow and Core Operations
Practice rebase, --onto, interactive rebase, autosquash, amend, cherry-pick conflict/abort/continue, and range-diff in one disposable unpublished history-editing lab.
Learning objectives
- Create and inspect a deliberately messy unpublished topic series.
- Use amend, fixup/autosquash, reorder, reword, and squash/fixup semantics safely.
- Rebase a topic onto a moved target and transplant a selected tail with --onto.
- Cherry-pick one change, inspect a conflict, abort safely, then resolve and continue.
- Use range-diff to compare old and rewritten versions of a patch series.
1. Build a disposable history-editing lab
Every branch in this lesson is local and explicitly unpublished. There is no remote account and no valuable repository involved.
Git Bash, Bash, or zsh
mkdir git-history-edit-lab
cd git-history-edit-lab
git init -b trunk
git config user.name "History Lab"
git config user.email "history-lab@example.invalid"
printf "mode=normal\nlimit=10\n" > service.ini
printf "# Service\n" > README.md
printf "color=blue\n" > policy.ini
git add service.ini README.md policy.ini
git commit -m "Create service baseline"
git status --short --branch
PowerShell file-creation alternative
New-Item -ItemType Directory git-history-edit-lab | Out-Null
Set-Location git-history-edit-lab
git init -b trunk
git config user.name "History Lab"
git config user.email "history-lab@example.invalid"
@('mode=normal','limit=10') | Set-Content service.ini
Set-Content README.md '# Service'
Set-Content policy.ini 'color=blue'
git add service.ini README.md policy.ini
git commit -m "Create service baseline"
git status --short --branch
2. Create an intentionally messy unpublished topic
git switch -c topic-metrics
# Edit service.ini to add:
# metrics=true
git add service.ini
git commit -m "Add metrics mode"
METRICS_COMMIT=$(git rev-parse HEAD)
# Add a short metrics section to README.md
git add README.md
git commit -m "WIP docs"
# Improve only the latest commit message
git commit --amend -m "Document metrics endpoint"
# Make a correction that belongs with the first topic commit
# Edit service.ini to add: metrics_path=/metrics
git add service.ini
git commit --fixup="$METRICS_COMMIT"
# Add an independent test/readiness note
printf "metrics smoke test\n" > tests.txt
git add tests.txt
git commit -m "Add metrics smoke test"
git log --reverse --format='%h %s' trunk..topic-metrics
Observe: amend already replaced the old “WIP docs” commit. The fixup commit names the change it should later be folded into.
3. Autosquash plus interactive reorder
Save the old tip only for comparison; this is still a disposable branch.
PRE_CLEAN=$(git rev-parse HEAD)
OLD_BASE=$(git rev-parse trunk)
git status --short
git log --graph --decorate --oneline --all --max-count=12
git rebase -i --autosquash trunk
Git opens the todo. With autosquash, the fixup! commit
is moved immediately after its target and its action becomes
fixup. The todo is applied top-to-bottom. A reviewable
plan can look conceptually like:
pick <A> Add metrics mode
fixup <F> fixup! Add metrics mode
pick <T> Add metrics smoke test
reword <D> Document metrics endpoint
Move the smoke-test line before documentation if that order better
explains implementation → verification → documentation. Change
pick to reword only if you intend to edit
that message. Save and exit.
4. Inspect the cleaned series, then compare versions
git status --short --branch
git log --reverse --format='%H %s' trunk..topic-metrics
git diff --check trunk...topic-metrics
git diff --stat trunk...topic-metrics
git range-diff "$OLD_BASE..$PRE_CLEAN" "trunk..topic-metrics"
git range-diff compares two
versions of a patch series. It pairs corresponding patches
where possible and shows how commit messages/order/content changed.
It is not a substitute for the final content diff; use both.
5. Rebase onto a moved target branch
Now simulate independent target work:
CLEAN_TIP=$(git rev-parse topic-metrics)
CLEAN_BASE=$(git rev-parse trunk)
git switch trunk
# Add the following line to service.ini without touching metrics lines:
# owner=platform
git add service.ini
git commit -m "Record service ownership"
git switch topic-metrics
git status --short
git rebase trunk
git log --graph --decorate --oneline --all --max-count=14
git range-diff "$CLEAN_BASE..$CLEAN_TIP" "trunk..topic-metrics"
Each topic commit is replayed on the new trunk tip.
Because the parent chain changed again, the cleaned topic receives
another set of replacement OIDs.
6. rebase --onto transplants only a selected tail
Use a stacked branch to make the three arguments concrete:
git switch trunk
git switch -c foundation-work
printf "foundation=true\n" > foundation.ini
git add foundation.ini
git commit -m "Prototype foundation"
git switch -c child-work
printf "child=true\n" > child.ini
git add child.ini
git commit -m "Add independent child change"
git log --graph --decorate --oneline --all --max-count=15
git rebase --onto trunk foundation-work child-work
git log --graph --decorate --oneline --all --max-count=15
git ls-tree -r --name-only child-work
Read the command as: “take commits on child-work after
foundation-work, and replay them onto
trunk.” The resulting child-work has
child.ini but not the unmerged
foundation.ini dependency.
7. Cherry-pick one independent fix
git switch trunk
git switch -c policy-fix
# Change policy.ini from color=blue to color=red
git add policy.ini
git commit -m "Use red policy mode"
POLICY_FIX=$(git rev-parse HEAD)
git switch trunk
git switch -c release-line
# Change the same line from color=blue to color=green
git add policy.ini
git commit -m "Use green release policy"
RELEASE_BEFORE=$(git rev-parse HEAD)
git cherry-pick "$POLICY_FIX"
The cherry-pick should stop because both commits changed the same base line differently. Inspect rather than guessing:
git status
git diff
git rev-parse CHERRY_PICK_HEAD
git show --stat --oneline CHERRY_PICK_HEAD
8. Abort once, then resolve and continue
First prove the abort safety path:
git cherry-pick --abort
git rev-parse HEAD
git status --short
HEAD should equal RELEASE_BEFORE and the
sequencer conflict state is gone. Now run the cherry-pick again,
resolve deliberately, stage, and continue:
git cherry-pick "$POLICY_FIX"
# Resolve policy.ini to the content your release policy requires.
git add policy.ini
git diff --staged
GIT_EDITOR=true git cherry-pick --continue
git show --stat --oneline HEAD
On PowerShell, use $env:GIT_EDITOR='true' for the one
continuation if you do not want an editor prompt, then remove that
temporary environment variable afterward.
9. Manual interactive operations: reword, squash, reorder, drop
For a small unpublished series:
git log --reverse --oneline trunk..topic-metrics
git rebase -i trunk
The editor is the control plane. Reorder lines to reorder replay;
use reword to edit a message; squash/fixup
to combine; and drop to intentionally remove. Never
delete a line casually when you mean “keep this commit.”
10. Challenge — choose the graph operation
- A private topic has three good commits but the target advanced. Which command family recreates the three commits on the new target?
- A private topic has a fixup commit for the first commit. Which commit/rebase combination avoids manual todo hunting?
- You need only the last two commits from a stacked topic, without its parent topic dependency. Which operation describes that transplant?
- A production fix exists on one branch and must be applied to a separate support line. Which operation replays only that selected change?
- After rewriting a local review series, which command compares old and new patch-series versions?
11. Cleanup
Git Bash / Bash / zsh
cd ..
pwd
rm -rf git-history-edit-lab
PowerShell
Set-Location ..
Get-Location
Remove-Item -Recurse -Force git-history-edit-lab
12. Knowledge check
Question 1. What does
git commit --fixup=<commit> prepare
for?
Question 2. What are the three conceptual arguments of
git rebase --onto NEWBASE UPSTREAM BRANCH?
Question 3. What does git cherry-pick --abort do
after a conflicted cherry-pick?
Question 4. Why use both git range-diff and a
normal content diff?
13. Summary
You rebuilt unpublished history with amend, autosquash, interactive
reorder/reword, normal rebase, and --onto; compared
patch-series versions with range-diff; and used
cherry-pick's conflict, abort, and continue paths. Every rewrite was
preceded and followed by graph/state inspection.
Authoritative references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.