Git for Engineers — Level by Level›03 · Branching and merging

Lesson 03 of 8 · Level 1 — Foundations

Branching and merging

Create branches for every change, bring them back with a fast-forward, a merge commit or a rebase, understand which history each produces, squash work-in-progress commits, and resolve conflicts calmly.

Beginner → Practitioner
Key wordsgit branchgit switchfast-forwardmerge commitgit mergegit rebaseinteractive rebasesquashmerge conflictconflict markers

Branches are cheap, so use them

Every change gets its own short-lived branch:

$ git switch -c fix/order-404
# edit, commit, commit
$ git push -u origin fix/order-404        # share it and open a pull request (lesson 04)

Short-lived branches (hours to a couple of days) merge cleanly; long-lived branches drift and collect conflicts.

Branching is taking a photocopy of a shared document to try out your edits in peace. Merging is carefully writing your edits back into the original, and a conflict is when someone else changed the same sentence while you were busy.

Three ways to bring a branch back

Before:        main:   A---B---C
                            \
               feature:      D---E

Fast-forward (only possible if main hadn't moved):   A---B---D---E
Merge commit:  A---B---C-------M          (M has two parents: C and E)
                        \     /
                         D---E
Rebase + fast-forward:  A---B---C---D'---E'   (D and E replayed as new commits)
Method History looks like Good for
Fast-forward A straight line Tiny changes, up-to-date branches
Merge commit Branches visible, with merge points Keeping the context of a feature branch
Rebase then fast-forward A straight line, feature commits on top Clean linear history on the main branch
Squash merge (on the Git server) One commit per pull request Simple history; WIP commits vanish

Pick one convention per repository and set it on the Git server (allowed merge methods on pull requests), so history stays consistent.

Rebase: replay your work on the latest main

$ git switch fix/order-404
$ git fetch origin
$ git rebase origin/main          # your commits are replayed on top of the latest main
$ git push --force-with-lease     # your branch was rewritten; only you use it

--force-with-lease refuses to overwrite the remote branch if someone else pushed to it meanwhile, unlike a plain --force.

Interactive rebase tidies your commits before review:

$ git rebase -i HEAD~4
pick 1a2b3c4 add order lookup
squash 5d6e7f8 wip
squash 9a8b7c6 fix typo
reword 0f1e2d3 handle missing orders

Resolving conflicts

$ git merge main
CONFLICT (content): Merge conflict in values-prod.yaml
$ git diff --name-only --diff-filter=U
values-prod.yaml
resources:
<<<<<<< HEAD
  requests: { cpu: 500m, memory: 512Mi }
=======
  requests: { cpu: 250m, memory: 768Mi }
>>>>>>> main
  1. Decide the correct result, which is often a combination (here maybe cpu: 500m, memory: 768Mi), not just "mine" or "theirs".
  2. Remove the markers, save, run the tests or a quick check.
  3. git add values-prod.yaml and git merge --continue (or git rebase --continue).
  4. Unsure? git merge --abort returns you to where you started.

Set git config --global merge.conflictStyle zdiff3 to also see the common ancestor's version inside the markers, which makes the intent of each side much clearer.

Try it: all three merges

  1. On a test repository, create feature with two commits while main stays still; merge with --ff-only and look at git log --graph.
  2. Repeat with a new commit on main first; merge with --no-ff and look again.
  3. Repeat once more but git rebase main on the feature branch, then fast-forward.
  4. Create a conflict on purpose (same line changed on both branches), resolve it with zdiff3 markers on, and finish the merge.
  5. Squash three WIP commits into one with git rebase -i.

Recap

  • One short-lived branch per change.
  • Fast-forward, merge commit, rebase or squash: know the history each produces and pick one convention.
  • Rebase only what hasn't been shared; push rewrites with --force-with-lease.
  • Conflicts: decide the correct result, remove markers, test, add, continue; --abort is always available.

This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.