Branches, pushing and pulling, merges, and merge conflicts

~9 min

The last lesson left forty engineers at peace, each working on a full clone of their own.

But all of that separate work owes a return to one shared history. The null-crash fix is coming home, and so is the loyalty redesign, and so is the menu update. Forty streams of edits must fold back into a single timeline without burying each other.

Git’s structure for this is delightfully science-fictional. Every piece of work happens in its own parallel universe, and the universes hold reunions.

What is a branch?

A Concept · lights on your mapbranchA private line of history where an engineer works without touching anyone else’s. Costs nothing to make, lives for days, and disappears once its work lands in main. is a fork in the timeline.

The shared, sacred history is usually called main, kept always clean, always shippable.

To build a feature, an engineer branches off main into a private timeline. There she commits freely (half-finished, broken, experimental), and nobody else is affected because nobody else is in her universe.

Branches get short, descriptive names, often prefixed with their author’s, which is why the figures below say things like mira/fix. And creating one is a single terminal command, over in a blink: git switch -c mira/fix-null-crash, “make this branch and step into it.”

A fork in the timeline
the shared history · advancing while Mira works
main
ABCDM
Mira branches offher work folds in as M
mira/fix
XYZ
three commits, made in peace · invisible until the reunion
Fig. 1 — a branch, and its reunion

Creating a branch is instant and free, which should sound wrong after the last lesson. Didn’t cloning copy the whole codebase?

It did, once, to bring the codebase to your machine. A branch copies nothing. It just marks a point in the copy you already have and declares that a new line of history grows from there — a bookmark, not a photocopy.

That cheapness sets the culture of one branch per feature or fix, made casually and deleted after merging. Engineers call these feature branches.

Meanwhile, thirty-nine other timelines advance in parallel, each engineer in their own universe, all splitting from and returning to the same main.

What are push and pull?

Parallel universes still need to stay acquainted.

The syncing happens through the shared repository on GitHub, with a verb for each direction:

  • Concept · lights on your mappushSending your local commits up to the shared copy, so they exist beyond your own machine. Paired with pull; together they keep forty clones current with each other. uploads your commits to the shared repository.
  • Concept · lights on your mappullFetching the team’s latest commits from the shared copy down into your clone, so your universe stops falling behind the others. The opposite of push. downloads others’ commits into your copy.

This is Module 2’s upload and download, reporting for duty in Git’s uniform. And the commands are literally the words themselves: git push, git pull, typed at the terminal.

The daily rhythm is habitual: pull in the morning to catch up on what the other universes did overnight; push when your commits are ready to exist beyond your laptop. An unpushed commit lives only on one machine, one spilled coffee away from never having existed.

What is a merge?

Parallel universes eventually have to reunite.

The Concept · lights on your mapmergeJoining two lines of history into one, bringing a branch’s commits home to main. Git combines the work itself unless both sides rewrote the same spot — then a human decides. folds a finished branch back into main, the moment M in the timeline above.

The astonishing part is that Git usually does it automatically.

You changed the payment file; your colleague changed the menu file. Git zips both timelines together without a question, and even edits to different parts of the same file usually combine cleanly.

Forty universes fold back into one shared history, mostly without human attention, and that quiet machinery is what makes forty engineers on one codebase possible at all.

What is a merge conflict?

The exception has a name that makes engineers sigh.

A Concept · lights on your mapmerge conflictGit’s refusal to guess: two branches rewrote the same lines in different directions, so the file gets both candidates fenced off for a human to settle. Minutes of judgment on a young branch; hours of it on a stale one. happens when two timelines edited the same lines, differently.

Erik renamed the delivery-fee function. Sam, in his universe, rewrote its insides under the old name. No algorithm can know which future was intended, so Git stops, fences off the disputed lines right in the file, and shows both versions:

What a conflict actually looks likeGit
1<<<<<<< HEAD
The fence opens. HEAD is the branch you’re standing on — here, main.
2def delivery_fee(order_total, member):
main’s side — Sam’s universe, keeping the old name…
3 fee = base_rate(order_total)
…over his rewritten insides.
4=======
The divider between the two versions.
5def calculate_delivery(order_total, member):
The branch’s side — Erik’s rename…
6 fee = order_total * 2
…over the old calculation he never touched.
7>>>>>>> erik/rename-fee-function
The fence closes, naming the branch it came from.
8 return fee
Unchanged in both universes, so it sits outside the fence. Git fences only the disputed region.

Those conflict markers are pasted by Git into the file itself. The engineer reads both versions, decides what the combined truth should be (keep one, keep the other, or write something incorporating both), deletes the markers, and commits the resolution.

Here, Erik decides both changes were right, and the file, after his edit:

The same lines, resolvedGit
1def calculate_delivery(order_total, member):
Erik’s rename, kept…
2 fee = base_rate(order_total)
…on top of Sam’s new insides, kept too — a combination no algorithm could have guessed.
3 return fee
Markers gone; Erik commits this as the resolution.

At small scale this is routine: a few minutes of judgment. The dread comes from scale. Resolving forty conflicts against five weeks of unfamiliar changes is a bad afternoon, and a risky one because every resolution is a fresh chance to break something.

Why engineers merge often

This leads to the cultural rule this lesson has been building toward.

Conflicts grow with divergence — how far two universes have drifted since they split. Merge a two-day branch and the universes barely differ. Let a branch live for a month while main absorbs forty merges, and the reunion is archaeology.

So “that branch has been open for a month” is said in the same tone as “that milk has been open for a month.”

The cure is cultural rather than technical. Keep branches small and merge them often, and the universes never get far apart. Module 12 will show you the automation that makes “often” nearly continuous. And its name, continuous integration, will suddenly make literal sense.

The mental model to remember

A branch is a fork in the timeline, a private universe split off from main, where an engineer commits freely without affecting anyone.

Main is the shared history: always clean, always shippable.

Push uploads your commits to the shared repository; pull downloads everyone else’s. Upload and download, in Git’s uniform.

A merge folds a branch back into main, automatic when changes don’t overlap, which is most of the time.

A merge conflict is the exception: same lines, changed differently, resolved by a human reading both versions between Git’s conflict markers.

Conflicts grow with divergence, so the culture is small branches, merged often.

You should now be able to picture the daily reality of a forty-engineer codebase: forty universes branching and folding, push and pull keeping them acquainted, and humans stepping in only where two futures collide.

Check — then the lesson continues

Mira's branch has been open for five weeks while main absorbed forty other merges. On her branch, the feature works perfectly. What does the team veteran predict about her merge?

▼ answer the check to continue ▼