Chapter 09Lesson 05~140 minutes

Checkpoint Lab — Rebase, Interactive Rebase, Cherry-Pick, Amend, and Safe History Editing

Checkpoint safe history editing by cleaning a messy private topic with amend/fixup/autosquash/reorder, rebasing it onto a moved base, comparing series, cherry-picking an independent fix, and recovering the original tip from reflog.

CheckpointAutosquashRange comparisonReflog recovery

Learning objectives

  • Predict and verify how amend, autosquash, reorder, and base movement replace commit IDs.
  • Compare messy, cleaned, and rebased patch-series versions with range-diff.
  • Cherry-pick an independent change into another branch without moving its source commit.
  • Locate the pre-rewrite topic tip in reflog and preserve it with a recovery branch.
  • Document the policy boundary for any future published rewrite and guarded remote replacement.

1. Checkpoint scenario — clean a messy private topic without losing its old tip

You will create a four-commit unpublished topic containing a bad message and a fixup commit, clean it with amend/autosquash/reorder, rebase the cleaned series onto a moved target, compare patch-series versions, cherry-pick an independent fix into another branch, and recover the original messy tip from the branch reflog.

2. Predictions before rewriting

  1. After amend changes only the latest commit message, will its OID remain the same?
  2. After autosquash folds a fixup into its target, how many independent topic commits should remain?
  3. After rebasing the cleaned topic onto a newly advanced trunk, will the topic commit OIDs stay stable?
  4. After the rewrite, can the original messy tip still appear in the local branch reflog even though the topic ref no longer points to it?

3. Setup and preflight

Git Bash, Bash, or zsh

mkdir git-rewrite-checkpoint
cd git-rewrite-checkpoint
git init -b trunk
git config user.name "Rewrite Checkpoint"
git config user.email "rewrite-checkpoint@example.invalid"
git config rebase.missingCommitsCheck error

printf "retries=1\ntimeout=5\n" > service.ini
printf "# Retry Service\n" > README.md
printf "alert=normal\n" > alerts.ini
git add service.ini README.md alerts.ini
git commit -m "Create retry service baseline"

git status --short --branch
git log --graph --decorate --oneline --all

PowerShell file-creation alternative

New-Item -ItemType Directory git-rewrite-checkpoint | Out-Null
Set-Location git-rewrite-checkpoint
git init -b trunk
git config user.name "Rewrite Checkpoint"
git config user.email "rewrite-checkpoint@example.invalid"
git config rebase.missingCommitsCheck error

@('retries=1','timeout=5') | Set-Content service.ini
Set-Content README.md '# Retry Service'
Set-Content alerts.ini 'alert=normal'
git add service.ini README.md alerts.ini
git commit -m "Create retry service baseline"
git status --short --branch
git log --graph --decorate --oneline --all

4. Create the deliberately messy unpublished topic

git switch -c topic-retry

# Change retries=1 to retries=3 in service.ini
git add service.ini
git commit -m "Add configurable retry count"
RETRY_COMMIT=$(git rev-parse HEAD)

# Add a Retry section to README.md
git add README.md
git commit -m "WIP docs"
WIP_OID=$(git rev-parse HEAD)

# Prediction: amend replaces WIP_OID
git commit --amend -m "Document retry behavior"
DOC_OID=$(git rev-parse HEAD)

# Add timeout_backoff=exponential to service.ini
git add service.ini
git commit --fixup="$RETRY_COMMIT"

printf "retry smoke test\n" > tests.txt
git add tests.txt
git commit -m "Add retry smoke test"

PRE_CLEAN=$(git rev-parse HEAD)
OLD_BASE=$(git rev-parse trunk)
git log --reverse --format='%H %s' trunk..topic-retry
git reflog -8 topic-retry

Verify prediction 1: WIP_OID and DOC_OID differ because amend created a replacement commit.

5. Autosquash and reorder the review series

Rewrite boundary: topic-retry is intentionally unpublished. Do not perform this exercise on a branch collaborators consume.
git status --short
git rebase -i --autosquash trunk

In the todo editor, Git should move the fixup! line directly after Add configurable retry count. Keep it as fixup. Reorder the remaining commits so the final story is:

pick   Add configurable retry count
fixup  fixup! Add configurable retry count
pick   Add retry smoke test
pick   Document retry behavior

Save and exit. Then verify:

CLEAN_TIP=$(git rev-parse HEAD)
git log --reverse --format='%H %s' trunk..topic-retry
git diff --check trunk...topic-retry
git range-diff "$OLD_BASE..$PRE_CLEAN" "trunk..topic-retry"

Verify prediction 2: four old topic commits become three review commits because the fixup is folded into its target.

6. Advance trunk, then rebase the cleaned topic

CLEAN_BASE=$(git rev-parse trunk)

git switch trunk
# Append owner=platform to service.ini without changing retry lines.
git add service.ini
git commit -m "Record service ownership"
NEW_BASE=$(git rev-parse HEAD)

git switch topic-retry
PRE_BASE_REBASE=$(git rev-parse HEAD)
git status --short
git rebase trunk

POST_BASE_REBASE=$(git rev-parse HEAD)
git log --graph --decorate --oneline --all --max-count=16
git range-diff "$CLEAN_BASE..$PRE_BASE_REBASE" "$NEW_BASE..$POST_BASE_REBASE"

Verify prediction 3: the final topic content/intent can stay equivalent while its commits receive new IDs because their parent chain now starts from NEW_BASE.

7. Create and cherry-pick one independent fix

git switch trunk
git switch -c alert-fix
# Change alerts.ini from alert=normal to alert=verbose
git add alerts.ini
git commit -m "Increase retry alert visibility"
ALERT_FIX=$(git rev-parse HEAD)

git switch trunk
git switch -c maintenance
git status --short
git cherry-pick "$ALERT_FIX"
git show --stat --oneline HEAD
git log --graph --decorate --oneline --all --max-count=18

The source alert-fix commit remains where it was. maintenance receives a new commit that replays its change.

8. Recover the original messy pre-clean tip through reflog evidence

Return to the topic and inspect its local branch reflog:

git switch topic-retry
git reflog show --date=local --format='%H %gs' topic-retry

Confirm that the saved PRE_CLEAN OID appears in the reflog output. Then derive the recovery OID from the reflog itself and preserve it:

RECOVER_OID=$(git reflog show --format='%H %gs' topic-retry | awk -v wanted="$PRE_CLEAN" '$1==wanted {print $1; exit}')
test -n "$RECOVER_OID"
git branch recovered-pre-clean "$RECOVER_OID"

git show --no-patch --oneline recovered-pre-clean
git log --graph --decorate --oneline --all --max-count=22

PowerShell equivalent for selecting the matching reflog line:

$match = git reflog show --format='%H %gs' topic-retry | Select-String $PRE_CLEAN | Select-Object -First 1
$RECOVER_OID = ($match.ToString() -split ' ')[0]
git branch recovered-pre-clean $RECOVER_OID
git show --no-patch --oneline recovered-pre-clean

Verify prediction 4: the main topic ref points to rewritten history, while the new recovery branch makes the old messy tip explicitly reachable again.

9. Produce a compact rewrite report

printf "old_messy_tip=%s\n" "$PRE_CLEAN"
printf "clean_before_base_move=%s\n" "$PRE_BASE_REBASE"
printf "new_target=%s\n" "$NEW_BASE"
printf "final_topic_tip=%s\n" "$POST_BASE_REBASE"
printf "recovered_old_tip=%s\n" "$(git rev-parse recovered-pre-clean)"

git log --reverse --format='%H %s' trunk..topic-retry
git diff --check trunk...topic-retry
git diff --stat trunk...topic-retry

In production, this kind of old/new OID mapping is useful when a review system or CI record needs to explain that a patch series was replaced.

10. If the topic had been published, stop before remote replacement

This lab intentionally has no remote. If team policy allowed rewriting a published review branch, the safe workflow would first fetch/inspect the remote and record the exact expected remote OID. Only then would a guarded update be considered:

# Conceptual policy pattern; do not run in this no-remote lab.
EXPECTED=<verified-old-remote-topic-oid>
git push --force-with-lease=refs/heads/topic-retry:$EXPECTED origin topic-retry:topic-retry

A lease failure is a stop signal, not permission to switch to --force.

11. Verification checklist

  • The lab repository is disposable and uses fake .invalid identity data.
  • The original topic had four commits after the baseline: implementation, amended documentation, fixup, and test.
  • Amend changed the documentation commit OID.
  • Autosquash folded the fixup into its target and the todo reorder produced a three-commit review series.
  • range-diff compared the messy and cleaned series.
  • After trunk advanced, rebase recreated the cleaned topic on the new base and a second range-diff compared versions.
  • An independent alert fix was cherry-picked into maintenance without moving the source branch.
  • The original messy tip appeared in the topic reflog and was preserved as recovered-pre-clean.
  • No shared remote history was rewritten and no plain force push was used.

12. Cleanup

Preflight: verify that you are deleting only git-rewrite-checkpoint.

Git Bash / Bash / zsh

git status --short --branch
cd ..
pwd
rm -rf git-rewrite-checkpoint

PowerShell

git status --short --branch
Set-Location ..
Get-Location
Remove-Item -Recurse -Force git-rewrite-checkpoint

13. Knowledge check

Question 1. Why did the autosquash cleanup reduce four topic commits to three?

Question 2. Why did rebasing the already-cleaned topic onto the moved trunk create another set of commit IDs?

Question 3. How did reflog help recover the pre-clean history?

Question 4. Why is the cherry-picked maintenance fix a different commit from the source fix?

Question 5. A published rewrite needs a force update. Why not use plain --force?

14. What Chapter 09 adds to a production Git operating model

You can now separate private history cleanup from shared-history governance, compare old/new patch series, transplant selected commits intentionally, abort uncertain sequencer operations, preserve old tips through reflog, and describe a guarded remote replacement policy. The goal is not “perfectly linear Git history”; it is controlled provenance with reviewable changes and recoverable decisions.

15. Chapter checkpoint summary

Rebase, interactive rebase, cherry-pick, and amend are all forms of graph reconstruction. Their power comes from creating new commits and moving refs. Their risk comes from doing that after other people or systems have made the old OIDs part of shared reality.

Next chapter

Undoing Changes, Reset, Restore, Revert, Reflog, and Lost-Work Recovery

Chapter 10 turns the recovery hints used here into a full state-based decision process: undo working-tree changes, index changes, local commits, published mistakes, and lost ref tips without reaching for the most destructive command first.

Authoritative references

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

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.