Chapter 09Lesson 02~120 minutes

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.

git rebase -i--ontorange-diffCherry-pick recovery

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.

Prediction: the topic branch should still contain the same intended final content, but the fixup commit disappears as an independent commit and reordered/reworded commits receive replacement OIDs.

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

  1. A private topic has three good commits but the target advanced. Which command family recreates the three commits on the new target?
  2. A private topic has a fixup commit for the first commit. Which commit/rebase combination avoids manual todo hunting?
  3. You need only the last two commits from a stacked topic, without its parent topic dependency. Which operation describes that transplant?
  4. A production fix exists on one branch and must be applied to a separate support line. Which operation replays only that selected change?
  5. After rewriting a local review series, which command compares old and new patch-series versions?

11. Cleanup

Confirm the path before deletion. This entire repository is disposable.

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.

Next

Decide which rewrite defaults belong in configuration and policy

Lesson 3 evaluates autosquash defaults, pull rebase behavior, update-refs, sequence editors, force-with-lease rules, and merge-versus-rebase provenance tradeoffs.

Authoritative references

 git-rebase
 git-cherry-pick
 git-commit
 git-range-diff

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.