Skip to content
C.W.K.
Stream
Lesson 01 of 05 · published

The Conflict Class You Cannot Remove

~11 min · concurrency, version-control, architecture, design

Level 0Wet Clay
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Why This One Is Different

The log race disappeared because a log entry is a small self-contained fact: a session can hand it to a central process and be done. A commit is not that. It is the state of a working tree that exists only on the machine where the work happened, and centralizing it would mean shipping the entire change to the writer — which relocates the problem rather than solving it.

So this conflict class gets serialized rather than removed, and the difference matters because serialization has costs that removal does not: somebody waits, a lock can be held by a session that died, and the whole thing needs a story for what happens when the holder never comes back.

What Actually Goes Wrong on a Parallel Day

The abstract version is "two commits conflict." The real version, measured on one busy day, is messier and worth knowing in advance.

The shared index. A repository has one staging area. A neighboring session's staged work is in it, and scoping your commit to your own paths does not remove what they staged — it only chooses what you add.

The slow hook. A pre-commit hook doing real work — regenerating assets, syncing to a service — turns each commit into a multi-minute operation. During that window every other session contends, and the lock file becomes the thing everybody is waiting on.

The three-way divergence. One machine is ahead, another is behind, a third has a dirty tree, and each of them is correct from where it is standing. There is no ordering that makes everyone's assumption true.

The neighbor's in-flight edit. Two sessions editing the same shared configuration file, one of them half done. Committing the file at that moment ships an incoherent state under your name.

The Shape of the Answer

Four moves, one per problem, and the next four lessons take them in turn: a lease that makes the landing indivisible, a scratch index so the shared one cannot leak into your commit, a deliberately chosen base so divergence is decided rather than discovered, and a rule about never hand-staging shared files that exists because the clever alternative was tried and was much worse.

When a race cannot be removed, serialize it — and then design for the holder that never comes back. Every lock needs an answer to "what if the session holding this is gone," and a lock without that answer converts a transient conflict into a permanent outage the first time somebody closes a laptop mid-run.

Code

One busy day, four distinct failures·text
SESSION A          SESSION B          SESSION C
(quest one)        (quest two)        (quest three)
     |                  |                  |
     |  stages 92 files across the repo    |
     |<-----------------|                  |
     |                  |                  |
  commit --only <my paths>                 |
     |   ^                                 |
     |   +-- does NOT unstage B's 92 files. one index per repo.
     |                                     |
     |                  |     edits shared config, half done
     |                  |<-----------------|
     |                                     |
  commit includes that half-edit if the path is named
     |
  pre-commit hook runs for 3 minutes (asset sweep)
     |   ^
     |   +-- index.lock held. B and C now blocked on A.
     |
  push -> REJECTED. remote moved while the hook ran.
     |   ^
     |   +-- and the commit already exists, on the wrong base.


FOUR PROBLEMS, FOUR MOVES
  shared index      -> build the commit in a scratch index
  slow hook         -> use plumbing; it does not fire hooks
  divergence        -> fetch first, choose the base, refuse if
                       genuinely diverged
  neighbor's edit   -> never name a shared file you did not
                       finish editing

External links

Exercise

List every shared mutable resource two of your automated processes can touch at once — a branch, a staging area, a deployment slot, a shared configuration file. For each, write down whether the contention can be removed by centralizing the writer or only serialized. Then, for every serialized one, write the answer to "what if the holder never comes back."
Hint
The resources people forget are the ones that are not obviously data: a branch, a build agent, a release channel, a shared directory in a package registry. They contend exactly like a database row, and they usually have no lock at all — the serialization is provided by the team being small enough that two people rarely try at once.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.