learn-github-for-builders-with-phoebe / Session 4 of 6
Learn GitHub for Builders with Phoebe · Session 4 of 6 · Tech track

Merge conflicts without fear

This is the fear-killer session. A merge conflict looks like git yelling at you in symbols, but it is the calmest thing git does: two branches changed the same lines, git refuses to guess which you meant, so it pauses and hands the decision to you. Nothing is broken and nothing is lost. Today you learn to read the markers, resolve like it is routine, and pick the right way to combine work - merge or rebase - every time.

🟡 Core Builders & analysts Terminal or Codespaces 45 min live + self-study
0-3 · Welcome 3-18 · Concepts 18-40 · Build-along 40-45 · Q&A
Part 0

Why this session kills the fear

Ask ten builders what scares them about git and nine say "merge conflicts". The fear comes from one wrong belief: that a conflict means you broke something. You did not. A conflict is git being honest - it hit two edits to the same line, it will not silently pick one, so it stops and asks. That is a feature. Once you have resolved five of them the panic is gone and it becomes a 30-second reflex. By the end of today you will manufacture a conflict on purpose, resolve it, and understand exactly when to merge versus rebase.

Live - presented in session Self-study - read after class ★ Build-along - type it in your terminal Running artifact: your my-project repo
★ What you walk out with today The ability to read the <<<<<<< ======= >>>>>>> markers on sight, a clean resolve-add-commit reflex, the abort escape hatch when you want out, and a clear rule for merge versus rebase (plus stash and cherry-pick as surgical tools) - so conflicts stop being scary and become routine.
Part 1 · read the markers

Why conflicts happen and how to read them 5 min live

A conflict happens for exactly one reason: two branches changed the same lines of the same file, and git cannot know which version you want. For every other change - different files, different lines - git merges automatically and you never notice. When it truly cannot choose, it does the responsible thing: it writes both versions into the file, wrapped in markers, and pauses so you can decide. Read the markers top to bottom: your side (HEAD) is above, their side (incoming) is below.

Same line, two edits - git writes both and asks you to choose. HEAD (main) edited line 1 # My Project - a tagline conflict-demo edited line 1 # My Project - built in public ! <<<<<<< HEAD # My Project - a tagline ======= # My Project - built in public >>>>>>> conflict-demo your side, above the divider their side, below Nothing is lost - both versions are right there in the file. Your job is to keep the correct combination and delete the three marker lines.
🔍 Click to zoom - HEAD side (yours) above the divider, incoming side (theirs) below
LiveThe three marker lines, decoded3 min▶
  • <<<<<<< HEAD - everything below this until the divider is your version, the branch you are currently on.
  • ======= - the fence. Above it is yours, below it is theirs. It marks nothing itself; it just separates the two sides.
  • >>>>>>> branch-name - everything from the divider up to here is the incoming version, from the branch you are merging in.
  • Conflicts are normal and safe. Git did not lose anything - it paused with both versions visible. git status lists every file still to resolve under "Unmerged paths".
# you merged and git hit a wall - status is your compass git status You have unmerged paths. (fix conflicts and run "git commit") Unmerged paths: both modified: README.md # open README.md - git wrote BOTH versions in, wrapped in markers <<<<<<< HEAD # My Project - a tagline ======= # My Project - built in public >>>>>>> conflict-demo
Self-studyWhy most merges have zero conflicts2 min read▶

Git merges at the line level, not the file level. Two people editing the same file rarely conflict - they conflict only when they touch the same lines. Different functions, different sections, different files all merge cleanly and automatically. This is why active teams merge dozens of branches a day and see conflicts only occasionally.

The practical takeaway: the way to reduce conflicts is not to avoid branching - it is to keep branches short-lived and pull main often, so your line and their line rarely drift apart before you combine them.

Part 2 · resolve it

Resolve it, in editor or on the web 4 min live

Resolving is four moves: open the file, choose the right combination, delete all three marker lines, then stage and commit. The choice is not always "mine or theirs" - very often the right answer is both, edited together into one coherent line. Editors help: VS Code and the GitHub web editor both show accept-current / accept-incoming / accept-both buttons above each conflict.

# you edited README to the final line and removed ALL three marker lines git add README.md # commit finishes the merge - git pre-fills a merge message for you git commit [main 9f2c1a0] Merge branch 'conflict-demo' # mid-rebase instead of a merge? this is the equivalent git rebase --continue # the escape hatch - undo everything, back to before the merge git merge --abort
LiveThe resolve loop, and the abort escape hatch2 min▶
  • Pick the combination, not a side. Read both versions, write the line you actually want - often a blend. There is no rule that says you must keep one intact.
  • Delete every marker line. The <<<<<<<, =======, and >>>>>>> lines must all be gone. If a build later complains about "unexpected <<<", you left a marker in.
  • Stage, then finish. git add the resolved file (that tells git "this one is handled"), then git commit for a merge, or git merge --continue / git rebase --continue depending on what you were doing.
  • Want out? git merge --abort. It resets you cleanly to the moment before the merge, as if you never started. No damage. Panic button, fully safe.
Real world

Every engineer remembers their first conflict - it looks like the terminal caught fire and it can eat 20 minutes of pure dread. The tenth one takes 30 seconds. Conflict resolution is pure pattern recognition; the only way through is reps. And the tempting mistake - avoiding branches so you never hit a conflict - backfires badly: it produces giant, weeks-old merges that conflict on everything at once. Small, frequent merges are how teams stay conflict-light.

Self-studyResolving in the GitHub web editor2 min read▶

When a PR reports "This branch has conflicts that must be resolved", GitHub offers a web conflict editor right in the browser - no local checkout needed. It shows the same markers with the same accept buttons, and a "Mark as resolved" then "Commit merge" flow. It is perfect for a small text conflict (a README, a config line) you want to clear without switching context.

For anything with logic - code that has to actually run after the merge - resolve locally in your editor where you can run the tests before you commit. The web editor cannot run your build.

Part 3 · two ways to combine

Merge vs rebase, and two surgical tools 6 min live

There are two ways to bring one branch's work into another. Merge ties the two histories together with a merge commit that has two parents - it preserves exactly what happened, when. Rebase lifts your commits off your branch and replays them one by one on top of the latest main - a clean, linear history, but it rewrites your commit hashes. Both are correct; they optimize for different things.

Merge - keeps both lines, adds a merge commit (2 parents) main feature commit merge commit Rebase - replays your commits on the main tip, one line replayed new hashes - history rewritten preserves what really happened
🔍 Click to zoom - merge curves the branch back with a merge commit; rebase replants your commits linearly and gives them new hashes
LiveThe golden rule, and when to reach for each3 min▶
The golden rule of rebase Never rebase commits you have already pushed and shared. Rebase rewrites history - it gives your commits new hashes - and if a teammate already has the old ones, you have just handed everyone two versions of the same work. Rebase your own local commits freely; leave shared history alone.
  • Merge for shared branches. Bringing a finished feature into main, or integrating a long-lived branch for a release - use merge. The merge commit documents when and where the integration happened, and it never rewrites anyone's history.
  • Rebase for tidying your own local work. Before you open a PR, rebase your messy local branch onto the latest main for a clean, linear story. Fine, because those commits are still yours alone.
  • git stash - shelve dirty work. Mid-edit and need to switch branches urgently? git stash tucks your uncommitted changes away, git stash pop brings them back. A clean pocket, not a commit.
  • git cherry-pick <hash> - grab one commit. Want just one bugfix from another branch without merging all of it? Cherry-pick copies that single commit onto your current branch by its hash.
Self-studyInteractive rebase to polish before a PR advanced2 min read▶

git rebase -i main opens an interactive editor listing your local commits, and lets you squash several messy commits into one, reword unclear messages, or drop a commit entirely before you open the PR - so reviewers see a clean, deliberate story instead of "wip", "fix", "fix again". It is the single best way to make your history read well. This is advanced and strictly for your own unpushed commits - the golden rule still applies: never interactive-rebase anything you have already shared.

Build-along 1 of 3

Manufacture and resolve a conflict ★ 10 min · everyone types

The fastest way to lose the fear is to cause a conflict on purpose in a safe place. We do exactly that in your my-project repo.

On main, edit line 1 of README.md to something like # My Project - a tagline. Then git add README.md and git commit -m "Add tagline to README".

Make the colliding branch from an earlier point: git switch -c conflict-demo HEAD~1. Edit the same line 1 differently - # My Project - built in public - then git add README.md and git commit -m "Reword README heading".

Go back and merge it in: git switch main, then git merge conflict-demo. Git stops and reports a conflict in README.md - this is the moment. Run git status and read "Unmerged paths".

Open README.md. Find the three markers, keep the combination you actually want (try blending both), and delete the <<<<<<<, =======, and >>>>>>> lines.

git add README.md, then git commit to finish the merge. Finally git log --graph --oneline --all - see the merge commit tie both lines together. You just did the scary thing. It was fine.

Build-along 2 of 3

Merge, rebase, or neither? ★ 6 min · everyone sorts

Now cement the judgment. Drag each situation to the right way of combining work. Green means correct - if you are unsure, guess and read the "why".

Build-along 3 of 3

The stash drill ★ 6 min · everyone types

Stash is the tool you did not know you needed until an urgent hotfix lands while your working tree is a mess. Feel it shelve and restore.

On any branch of my-project, make a dirty edit - change a line in notes.md but do not commit it. Run git status and see it modified.

git stash. Run git status again - your working tree is clean, the edit is shelved. It did not disappear; it is in the stash.

git switch main (or any other branch), do a quick imaginary hotfix, then git switch back to where you were.

git stash pop. Your dirty edit is restored exactly as it was. That is the whole loop: shelve, switch, restore.

Optional cherry-pick: run git log --oneline conflict-demo, copy one commit hash, then on main run git cherry-pick <hash> to graft just that one commit across.

Stash names its shelves git stash list shows every shelved change; git stash pop takes the most recent, git stash apply stash@{1} takes a specific one. It is a stack, so you can shelve more than one thing.
After the session

This week ◐ 25 min total

Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · In a conflict, what does the ======= line separate?

The divider fences the two versions: everything above it is HEAD (your current branch), everything below it up to the >>>>>>> marker is the branch you are merging in.

2 · What is the golden rule of rebase?

Rebase rewrites history and gives commits new hashes. If others already have the old commits, rebasing shared history hands everyone conflicting copies. Rebase your local work only.

3 · What does git merge --abort do?

It is the fully safe escape hatch - it undoes the in-progress merge and returns your working tree to exactly where you were before, as if nothing happened.

Source material

Official GitHub Skills coverage

This session maps to GitHub's own free CLI-based Skills exercises. Here is what today covers in full, and what the official exercises add.

✓Resolve merge conflicts (skills/resolve-merge-conflicts)full - reading markers, resolving, add + commit, abort: Parts 1-2 + Build-along 1
✓Introduction to Git (merge / rebase / stash)the combine model and surgical tools - Part 3 + Build-along 3
✓cherry-picktool level - Part 3 + optional Build-along 3 step
◐Interactive rebase (squash / reword)self-study card + homework - advanced, own commits only
◐rerere (reuse recorded resolution)mention only - git can replay past resolutions; out of scope today

Session 4 cheat sheet · pin this

Marker anatomy<<<<<<< HEAD = yours (above) · ======= = divider · >>>>>>> branch = theirs (below).
Resolve loopEdit to the right combination → delete all 3 markers → git add → git commit.
Escape hatchgit merge --abort resets you to before the merge. Fully safe.
Golden ruleNever rebase commits you have pushed and shared. Local commits only.
Merge vs rebaseMerge = shared branches, true history, two parents. Rebase = tidy your own local line before a PR.
Surgical toolsgit stash / stash pop to shelve dirty work · git cherry-pick <hash> for one commit.