Skip to content
GitTree

Lesson 18 · History and integration

Merge branches with diverged history

Combine the published workflow-card feature with main's independent accessibility and footer changes. Verify a real two-parent merge and the complete resulting page.

Progress saved in this browser.

Playing loads the video from YouTube (privacy-enhanced mode).

English narration · English and Arabic captions

Open the video pageWatch on YouTube

What you will learn

  • Recognize divergence from ancestry.
  • Choose an explicit merge recording mode.
  • Verify both parents and combined content.
  • Keep local merge separate from server publication.

Before you start

Start where lesson 17 ended: main with Maya's README commit, clean; the published feature/pricing-cards is still F1, branching from H5. You save and commit MAIN_ACCESSIBLE as preparation, so that main and the feature each have independent commits.

The video was recorded with Git 2.52.0 and GitTree 2.0 on Ubuntu 24.04: the page, its commit and the merge were done in the app; the before state, the refused fast-forward in a separate copy and the checks (including the project's own lint, test and build) ran in the terminal. 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

Divergence means neither tip is simply the descendant to which the other branch can fast-forward. Git finds a common ancestor and combines changes relative to it. A branch name alone cannot tell you whether a merge commit is needed.

A merge commit records two parents in order. First parent is the checked-out branch's prior tip; second is the merged side. Existing feature commits keep their identities; a new merge commit connects their ancestry.

No textual conflict is not proof of semantic correctness. Verify focusable main, workflow section and Leo's reminder in the complete file; run existing checks. A local merge does not update origin until a separate authorized push.

Preparation and merge move local main/HEAD and update index/work. The feature ref remains F1. Both origin branches and v0.1.0 retain their prior tips.

Prepare the exact project state

On main save MAIN_ACCESSIBLE, stage only index.html and commit fix: make the main landmark focusable. This makes the native/app merge input explicit; do not commit the already combined MERGED file before merging.

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 — MAIN_ACCESSIBLE

File excerpt · html
<!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>
  </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>

index.html — MERGED

File excerpt · html
<!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>
  </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>

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.

  1. Save MAIN_ACCESSIBLE through Show Files → index.html → Save; review only tabindex addition.
  2. Show Working Changes; Stage File index.html; commit fix: make the main landmark focusable with ordinary options off.
  3. Inspect main and feature/pricing-cards graph ancestry; keep main checked out.
  4. Under Local open the feature folder, right-click pricing-cards → Merge feature/pricing-cards into main. The dialog follows with Record it as.
  5. In Record it as the choices are Fast-forward if possible, else a merge commit; Always a merge commit; Fast-forward only; and Squash into staged changes (no commit). Select Always a merge commit. Cancel if the actual preview shows unexpected paths or conflicts.
  6. Choose Merge once and wait for actual completion. Do not substitute Squash into staged changes.
  7. Inspect the resulting commit's two parents and compare full index.html to MERGED; verify all three independent changes.
  8. Run the local checks and clean-status queries; leave main at the local merge, with no Push After Commit. The app's own merge subject is “Merge branch 'feature/pricing-cards'”; it does not have to match the native message below.

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

After saving MAIN_ACCESSIBLE, native preparation and merge:

Command · bash
git add -- index.html
git commit --quiet -m "fix: make the main landmark focusable"
git branch course-before-merge
git merge --quiet --no-ff feature/pricing-cards --message "merge: combine workflow cards with accessibility"
git log -1 --format=%s
git rev-list --parents -n 1 HEAD
git status --short

Actual subject:

Output
merge: combine workflow cards with accessibility

The parent query emits actual merge SHA followed by exactly two parent SHAs; IDs vary. The complete merged index.html matched MERGED byte-for-byte in the fixture; status was empty. The explicit native subject need not match the app's generated subject: accept the actual app message if ancestry/content agree, never overlay a fake native message.

Command · bash
npm run --silent lint
npm test -- --test-reporter=tap
npm run --silent build

Run these against the merged checkpoint; source text and parent count alone do not prove the checks. The fixture suite has six tests. A separate ff-only attempt on the diverged input must refuse rather than silently choose this merge mode.

Result

Where you end: Main points to merge M with first parent the prepared main tip and second parent F1; full MERGED page contains workflow cards, Leo footer and focusable main. Index/work clean; no remote push.

Common mistakes

  • Merging the wrong direction.
  • Calling a squash a two-parent merge.
  • Trusting no-conflict preview as semantic proof.

If something goes wrong

If a real merge stops, keep its operation state and use the conflict/abort workflow taught later; do not issue an unrelated reset. Before a completed native merge, course-before-merge preserves only the old committed tip, not arbitrary working bytes.

Check your understanding

Answer each question, then read why. Questions marked “Required” count toward completing the lesson.

  1. Question 1 of 6

    What makes a merge commit distinct?

    Choose one answer.

  2. Question 2 of 6

    Which evidence is needed?

    Choose every answer that applies.

  3. Question 3 of 6
    Required

    What happens to F1's identity?

    Choose one answer.

  4. Question 4 of 6
    Required

    Choose ff-only on this diverged input: result?

    Choose one answer.

  5. Question 5 of 6

    No textual conflict means tests unnecessary?

    Choose one answer.

  6. Question 6 of 6
    Required

    What is the final scope?

    Choose every answer that applies.

0 of 6 correct

Answer the required questions correctly to complete the lesson.

Checked in this browser.

Practice

Verify exact MERGED bytes and two actual parents, with F1 unchanged. Predict that Fast-forward only on the original diverged input refuses; test only in a separate 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

  • Divergence is an ancestry relationship.
  • Merge preserves old commit identities.
  • Content and parent checks are both required.

Glossary terms introduced

Merge — دمج; merge commit — إيداع دمج; common ancestor — سلف مشترك; first parent — الأب الأول.

Video transcript

The narration of the video, cue by cue.

Show the transcript
  1. Start from the exact checkpoint.
  2. Name the branch, index and working version.
  3. Prepare only the isolated course copy.
  4. Prepare the independent accessibility change.
  5. Record only that intended main change.
  6. Inspect the actual diverged ancestry.
  7. Merge the feature into current main.
  8. Choose the recording mode deliberately.
  9. Wait for the real merge result.
  10. Verify both parents and combined content.
  11. Keep this merge local until reviewed.
  12. What makes a merge commit distinct?
  13. Ancestry is defined by parent IDs, not message or color.
  14. Which evidence is needed?
  15. A structurally valid merge can still have wrong content.
  16. What happens to F1's identity?
  17. Merge connects existing commits rather than replaying them.
  18. Choose ff-only on this diverged input: result?
  19. Neither tip is the required descendant for a simple fast-forward.
  20. No textual conflict means tests unnecessary?
  21. Semantic correctness needs content review and tests.
  22. What is the final scope?
  23. No push is part of this local merge.
  24. Verify the actual result, not just a message.
  25. Predict the changed input before acting.
  26. Preserve useful work before recovery.
  27. Prove the checkpoint before continuing.
  28. Keep the verified result for the next step.