Lesson 20 · History and integration
Rebase unpublished work onto a new base
Replay one unpublished signup commit on an independently updated base. Preserve the old tip and verify new identity, new parent and unchanged intended signup content.
- Level: Intermediate
- 8 min read
- 5 min video
- Updated
- Before this lesson: Merge branches with diverged history
Progress saved in this browser.
Playing loads the video from YouTube (privacy-enhanced mode).
What you will learn
- Identify the exact private replay range.
- Protect old committed history before replay.
- Recognize recreated commit identities.
- Verify parent and full resulting tree.
Before you start
Start from a separate copy of lesson 18's result (main is the merge M, clean): the private topic feature/signup-form holds one commit S, updated-main holds one different commit N, both on M, and rescue/signup-before-rebase also points at S. The topic is checked out, clean and unpublished.
The video was recorded with Git 2.52.0 and GitTree 2.0 on Ubuntu 24.04: the private topic and the newer base were built in the terminal; the rebase, its dialog and the checks of the result were done in the app; the result was read back in the terminal. The native replay below was run in a disposable copy and gave the same result. Nothing was run on macOS or Windows, and Ubuntu is the only Linux system recorded. GitTree's source Git floor is 2.39.0.
GitTree asks you to sign in; the Free plan then covers every step here. No provider account, Pro/trial, API credential or internet service is needed. A local bare origin is not GitLab or CI. All identities use example.com; never run this lesson inside a source checkout.
Make mutations through either GitTree or the native path at identical inputs, not both consecutively. Read-only verification can follow either. Any preparation described as terminal work is labeled native preparation, never an invented app feature.
Concept and state effects
Rebase selects commits unique to the current topic and replays their changes onto a new base. It does not move the old commits themselves; it creates new commits with new parents and usually new IDs.
The source branch must be the intended current branch. In this fixture S adds signup and N adds a different document, so replay is conflict-free, but that does not make arbitrary rebases safe.
Published history is a coordination boundary. These commits are intentionally private; do not rebase the already published pricing feature merely to make its graph straight. A rescue ref protects committed ancestry, not unsaved text.
Feature and HEAD advance S→S′; index/work become the combined tree. N/updated-main, rescue S and original main/M stay fixed. No server mutation or automatic push.
Prepare the exact project state
Begin from a separate ordinary copy of the project as lesson 18 left it (main is the merge M). The original gittree-features stays preserved; do not run this scenario in the original or a source checkout. Then perform the exact preparation below. Repo-local demo signing is off and GitTree Demo <demo@example.com> is the identity.
Complete file inputs
Save only at the phase named below. These are full UTF-8/LF bodies with a final newline; never paste Markdown fences. Unchanged runnable files inherit the named input. Versions in separate variants must not overwrite the original.
index.html — SIGNUP
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">See your work clearly.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
<section aria-labelledby="signup-title">
<h2 id="signup-title">Try the demo form</h2>
<form id="signup-form" novalidate>
<label for="demo-email">Demo email</label>
<input id="demo-email" name="email" type="email" autocomplete="off" aria-describedby="signup-hint">
<p id="signup-hint">Use a fictional example.com address. Nothing is sent.</p>
<button type="submit">Check the address locally</button>
<p id="signup-result" role="status"></p>
</form>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>docs/integration-note.md — DOC_MERGE
# Integration review
This note was written on main while signup work was private.In GitTree
Palette: Command+Shift+P (Ctrl+Shift+P on Ubuntu); type the exact named command and select it. Named-ref actions use that row's context menu, not an argument-free palette shortcut.
- Prepare the exact divergence and rescue branch using the labeled native setup below; no published branch is rewritten.
- In the app confirm feature/signup-form checked out, clean and unpublished; inspect S and N.
- Right-click updated-main in the graph → Rebase feature/signup-form onto updated-main; the dialog names the current branch and the target.
- Read Options for this rebase. Leave Stash local changes and put them back and Move the branches that point into these commits off. The dialog says the old feature/signup-form is kept under refs/ogt/trash.
- Choose Rebase feature/signup-form once; wait for the notice that the rebase finished. If it stops, keep its operation state rather than clicking again.
- Inspect S′ parent N and subject. Compare actual old/new IDs, not model labels as terminal output.
- Inspect full SIGNUP and DOC_MERGE in the resulting tree; rescue branch still points to old S.
- Verify clean status and no rebase operation; leave original main/M and all server refs alone.
For every ordinary commit: Summary is the stated subject; Description empty; Amend Previous Commit, Skip Hooks, Add Signed-off-by, Different Author, Push After Commit and Allow Empty Commit off; no co-authors. Stage only the named files, then Commit Changes to N Files once (File for one), or Command+Enter as an alternative. Wait for the real result. A lesson that explicitly amends changes only that stated option.
In the terminal
In a separate clean lesson 18/M copy, create the private topic:
git switch --create feature/signup-formPut the saved SIGNUP file over index.html (the video saved the lesson's files in ~/Downloads and uses cp ~/Downloads/SIGNUP.html index.html), then:
git add -- index.html
git commit --quiet -m "feat: add the local signup demonstration"
git branch rescue/signup-before-rebase
BASE_SHA="$(git rev-parse HEAD~1)"
git switch --quiet --create updated-main "$BASE_SHA"On updated-main put DOC_MERGE at docs/integration-note.md (cp ~/Downloads/DOC_MERGE.md docs/integration-note.md), then:
git add -- docs/integration-note.md
git commit --quiet -m "docs: add the integration review"
git switch --quiet feature/signup-formBASE_SHA is the measured M parent before the private signup commit. Both topic and updated-main now have one independent commit; rescue/signup-before-rebase retains the old topic. Nothing from this topic is published.
Native replay alternative:
git rebase --quiet --no-autostash --no-update-refs --no-autosquash updated-main
git log -1 --format=%s
git rev-parse HEAD HEAD^ updated-main rescue/signup-before-rebase
git status --shortObserved subject:
feat: add the local signup demonstrationActual HEAD differs from rescued S; HEAD^ equals updated-main/N. The independent document and exact SIGNUP body both remain; short status is silent. Stop on an unexpected published/dirty input instead of adding force options. For the conflict variant, see lesson 23; do not treat a stopped rebase as already finished.
Result
Where you end: feature/signup-form points S′, parent N, with signup plus DOC_MERGE; old S survives in rescue/signup-before-rebase. No operation active, clean; main/M and server unchanged.
Common mistakes
- Assuming a straight graph means the old commit ID survived.
- Treating the alternative pane as the original checkpoint.
- Repeating a completed mutation after app success.
If something goes wrong
Before replay the rescue branch retains S. If the operation stops, inspect the banner and resolve or explicitly Abort; a completed rebase is not aborted by rebase --abort. Never assume native replay wrote a GitTree journal.
Check your understanding
Answer each question, then read why. Questions marked “Required” count toward completing the lesson.
0 of 6 correct
Answer the required questions correctly to complete the lesson.
Checked in this browser.
Practice
Prove new HEAD differs from rescue, its parent equals N and full signup/document bytes agree. Predict conflicts if both sides change the same hero line, in a separate lesson 23 copy.
Your own confirmation: the site cannot see your computer.
To complete the lesson, answer the required questions correctly and confirm the practical exercise.
Recap
- Rebase recreates commits.
- Choose current branch and target explicitly.
- Private history and recovery scope matter.
Related
Glossary terms introduced
Rebase — إعادة تأسيس; replay — إعادة تطبيق; rescue ref — مرجع حفظ.
Video transcript
The narration of the video, cue by cue.
Show the transcript
- Start from the exact checkpoint.
- Name the branch, index and working version.
- Prepare only the isolated course copy.
- Prepare the private divergence and rescue ref.
- Check which branch is actually current.
- Choose the intended new base.
- Keep unrelated replay options off.
- Wait for the actual replay result.
- The new parent means a new commit identity.
- Verify the full combined content.
- Preserve the old tip without publishing it.
- What is replayed?
- The selected commit range is recreated on the new base.
- What must be checked?
- Scope determines which commits and refs may move.
- S replayed on N: parent?
- The new commit S′ is parented by N.
- Change input: same hero line changed on both sides.
- Replay can stop; resolution and continuation are explicit.
- Can --abort undo an already finished rebase?
- Abort needs an active operation; completed recovery needs preserved evidence.
- What proves this result?
- Messages can stay the same while identities change.
- Verify the actual result, not just a message.
- Predict the changed input before acting.
- Preserve useful work before recovery.
- Prove the checkpoint before continuing.
- Keep the verified result for the next step.