Three-Way Merge: When Branches Truly Diverge

Both sides genuinely moved. Trace the real common ancestor by hand before git does the actual three-way merge.

feature/spice-rack gains its own real commits while master, independently, gains a genuinely different one. Neither side is "behind" the other in the simple sense from Lesson 2.3.1 — this is real, true divergence, and the merge that follows has to be a genuine three-way comparison, not a simple pointer move.\n\nBefore running the merge, this lesson traces by hand exactly what git itself will compare: the real common ancestor (found with git merge-base), master's real tip, and the branch's real tip. Seeing all three explicitly is what makes it clear why git can often combine genuinely independent changes automatically.

Real, Independent Work on Both Sides

# feature/spice-rack gets its own real commits
# master, separately, gains freezer-labels.md

Neither side is a simple ancestor of the other anymore — genuine, true divergence.

Tracing the Real Common Ancestor by Hand

git merge-base master feature/spice-rack

The exact real commit both branches share as their most recent common point — found by git, but genuinely knowable by hand too, by reading the log carefully.

The Three Real Commits Git Actually Compares

A three-way merge is named for exactly three inputs: the real common ancestor, master's real current tip, and the branch's real current tip. git compares each side's changes against the shared ancestor — which is precisely why independent changes to different files (or different lines) usually combine automatically, with no conflict at all.

Performing the Real Merge

git merge --no-ff feature/spice-rack -m "Merge pull request: spice rack guide"

A real merge commit with two genuine parents — master's tip and the branch's tip — both real, independent lines of work combined into one.

git merge-base a b

Finds the real, most recent commit both a and b share as an ancestor — the actual starting point git uses for a three-way merge. Confirmed directly in this lab: it returned the exact real merge commit both branches had genuinely diverged from.

Three-way merge

A merge where git compares three real inputs — the common ancestor, and each side's current tip — rather than simply moving a pointer. Confirmed directly in this lab combining two genuinely independent files (spice-rack.md and freezer-labels.md) with zero conflict, since neither side touched what the other changed.

🌱 Create Real, Independent Work on Both Sides

Give the feature branch its own commits, and let master gain a genuinely separate one.

cd ~/team-recipes && git switch -c feature/spice-rack
cd ~/team-recipes && printf 'Spice Rack\n\nOrganize spices alphabetically for quick access.\n' > spice-rack.md
cd ~/team-recipes && git add spice-rack.md
cd ~/team-recipes && git commit -m 'Add spice rack organization guide'
cd ~/team-recipes && printf '\nReplace ground spices every 12 months for best flavor.\n' >> spice-rack.md
cd ~/team-recipes && git add spice-rack.md
cd ~/team-recipes && git commit -m 'Add spice freshness guidance'
cd ~/team-recipes && git push -u origin feature/spice-rack

student@lab:~$ cd ~/team-recipes && git switch -c feature/spice-rack Switched to a new branch 'feature/spice-rack' student@lab:~$ cd ~/team-recipes && printf 'Spice Rack\n\nOrganize spices alphabetically for quick access.\n' > spice-rack.md student@lab:~$ cd ~/team-recipes && git add spice-rack.md student@lab:~$ cd ~/team-recipes && git commit -m 'Add spice rack organization guide' [feature/spice-rack 6e16df9] Add spice rack organization guide 1 file changed, 3 insertions(+) create mode 100644 spice-rack.md student@lab:~$ cd ~/team-recipes && printf '\nReplace ground spices every 12 months for best flavor.\n' >> spice-rack.md student@lab:~$ cd ~/team-recipes && git add spice-rack.md student@lab:~$ cd ~/team-recipes && git commit -m 'Add spice freshness guidance' [feature/spice-rack 6e71ad6] Add spice freshness guidance 1 file changed, 2 insertions(+) student@lab:~$ cd ~/team-recipes && git push -u origin feature/spice-rack Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 431 bytes | 431.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To ../recipes-origin.git * [new branch] feature/spice-rack -> feature/spice-rack branch 'feature/spice-rack' set up to track 'origin/feature/spice-rack'.

🔀 Let Master Diverge Too

Add a genuinely independent commit directly to master.

cd ~/team-recipes && git switch master
cd ~/team-recipes && printf 'Freezer Labels\n\nDate and label everything before freezing.\n' > freezer-labels.md
cd ~/team-recipes && git add freezer-labels.md
cd ~/team-recipes && git commit -m 'Add freezer labeling recipe note'
cd ~/team-recipes && git push

student@lab:~$ cd ~/team-recipes && git switch master Switched to branch 'master' Your branch is up to date with 'origin/master'. student@lab:~$ cd ~/team-recipes && printf 'Freezer Labels\n\nDate and label everything before freezing.\n' > freezer-labels.md student@lab:~$ cd ~/team-recipes && git add freezer-labels.md student@lab:~$ cd ~/team-recipes && git commit -m 'Add freezer labeling recipe note' [master 80096d8] Add freezer labeling recipe note 1 file changed, 3 insertions(+) create mode 100644 freezer-labels.md student@lab:~$ cd ~/team-recipes && git push Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 342 bytes | 38.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 To ../recipes-origin.git 4a2fc3b..80096d8 master -> master

📍 Trace the Real Merge Base by Hand

Find the exact common ancestor, and confirm the three real commits git will actually compare.

cd ~/team-recipes && git merge-base master feature/spice-rack
cd ~/team-recipes && git log --oneline master -1
cd ~/team-recipes && git log --oneline feature/spice-rack -1

student@lab:~$ cd ~/team-recipes && git merge-base master feature/spice-rack 4a2fc3ba85ad051414aaf347eb7ce61cf943beab student@lab:~$ cd ~/team-recipes && git log --oneline master -1 80096d8 (HEAD -> master, origin/master, origin/HEAD) Add freezer labeling recipe note student@lab:~$ cd ~/team-recipes && git log --oneline feature/spice-rack -1 6e71ad6 (origin/feature/spice-rack, feature/spice-rack) Add spice freshness guidance

🔗 Perform the Real Three-Way Merge

Merge, and confirm git combined both genuinely independent changes with no conflict.

cd ~/team-recipes && git merge --no-ff feature/spice-rack -m 'Merge pull request: spice rack guide'
cd ~/team-recipes && git push
cd ~/team-recipes && git log --oneline --graph -5

student@lab:~$ cd ~/team-recipes && git merge --no-ff feature/spice-rack -m 'Merge pull request: spice rack guide' Merge made by the 'ort' strategy. spice-rack.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 spice-rack.md student@lab:~$ cd ~/team-recipes && git push Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 308 bytes | 102.00 KiB/s, done. Total 2 (delta 1), reused 0 (delta 0), pack-reused 0 To ../recipes-origin.git 80096d8..f18174f master -> master student@lab:~$ cd ~/team-recipes && git log --oneline --graph -5 * f18174f (HEAD -> master, origin/master, origin/HEAD) Merge pull request: spice rack guide |\ | * 6e71ad6 (origin/feature/spice-rack, feature/spice-rack) Add spice freshness guidance | * 6e16df9 Add spice rack organization guide * | 80096d8 Add freezer labeling recipe note |/ * 4a2fc3b Merge pull request: fridge organization tips |\

Lab 2.3.2 complete. A real, true divergence, traced by hand and merged cleanly:\n\n\n Real divergence on both sides created : ✅ confirmed\n Merge base traced by hand : ✅ git merge-base\n Three real inputs identified : ✅ base, both tips\n Genuine three-way merge, no conflict : ✅ confirmed\n

Enable JavaScript to run the live terminal and track your progress.