Skip to main content
RunBook Academy

Git, CI/CD & GitOpsX · Merge ConflictsConflicts

Conflict prevention — short branches, small commits, rerere, and the human layer

Intermediate⏱ ~20 mingit

What you'll learn

  • Apply the workflow rules that reduce the rate of merge conflicts (short branches, small commits, frequent rebase, communication)
  • Configure `rerere.enabled true` and explain how `git rerere` remembers past conflict resolutions
  • Use CODEOWNERS and file-level ownership to reduce cross-engineer conflicts on shared files
  • Recognise when a merge conflict signals a workflow problem rather than a per-engineer mistake
  • Distinguish preventive measures that change the merge model from those that only change the resolution step

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

Most of this part has been about conflict resolution — what to do when the algorithm stops and asks a human. The last lesson in Part X is about conflict prevention. A merge conflict is a surface symptom: two branches have moved in parallel long enough that the algorithm cannot combine their changes automatically. Reducing the rate of conflicts is a workflow problem; reducing the cost of the conflicts that do occur is a tooling problem. git rerere is the most underused conflict tool in the Git toolbox.

Why conflicts happen

Two branches diverge and stay divergent. Each commits new content to overlapping files. When they meet for the merge, the algorithm compares the base against each side and finds that both sides touched the same lines. The longer the divergence and the larger the edits, the larger the conflict:

flowchart LR
    A["Branch A\ncreated"] --> B["Branch A\n3 commits\nover 2 days"]
    A --> C["Branch B\ncreated"]
    C --> D["Branch B\n5 commits\nover 4 days"]
    B --> E["Merge A\n20% files overlap"]
    D --> E
    E -->|"probability of conflict"| F["Conflict\nper file"]

The diagram illustrates the rule of thumb: a branch that diverges for two days with three commits produces fewer conflicts than one that diverges for two weeks with twenty commits. The relationship is not linear, but the direction is clear. Prevention is mostly about reducing branch age and commit count per file.

Prevention rule 1 — short-lived branches

The branch lifetime is the single largest factor. A branch that lives for one day with one well-scoped change rarely conflicts; a branch that lives for two weeks with daily commits over a major refactor almost always does.

# A short-lived branch — feature, merge, delete
git checkout -b feature/update-k8s-limits
# ... edits ...
git commit -m "Increase api-server memory limit to 1Gi"
# 30 minutes later: PR opened, reviewed, merged, branch deleted

# The opposite — long-lived feature branch
git checkout -b feature/q4-network-overhaul
# 14 days, 47 commits, in periodic conflict with main

The operational rule for an infrastructure team: “branches should be merged within 24 hours of creation, or they are too big.” This is enforced by branch protection rules that auto-delete stale branches, and by team norms that surface PRs as soon as the first commit lands.

Prevention rule 2 — small atomic commits

A commit that changes one concern at a time can be reviewed independently, reverted independently, and rebased independently. A commit that bundles five unrelated changes forces all five to be merged, reverted, or rebased together:

# Atomic — five commits on a single branch
git commit -m "Bump api memory limit"
git commit -m "Add readiness probe to api"
git commit -m "Bump worker count to 4"
git commit -m "Add ingress TLS annotation"
git commit -m "Document the new resource shape"

# Bundled — one commit with everything
git commit -m "Various improvements to the api deployment"

When branch A has five atomic commits and branch B has five atomic commits to the same file, each commit can be merged or rebased independently — the conflict is per-commit, not per-branch, and is correspondingly smaller. When branch A has one bundled commit, the conflict is the entire bundled commit’s diff against B.

Prevention rule 3 — frequent rebase

A branch that rebases against main once a day is much easier to merge than one that rebases once at the end of the week. The frequent rebase surfaces the conflict while it is still small:

# Daily: fetch and rebase
git fetch origin main
git rebase origin/main
# CONFLICT (content): Merge conflict in terraform/iam/main.tf
# 2 lines of conflict. Resolve in 30 seconds.

# End-of-week: fetch and rebase
git fetch origin main
git rebase origin/main
# CONFLICT (content): Merge conflict in terraform/iam/main.tf
# CONFLICT (content): Merge conflict in terraform/iam/roles.tf
# CONFLICT (content): Merge conflict in terraform/iam/outputs.tf
# 8 hunks over 3 files. Resolve in 30 minutes.

The daily rebase produces a small, cheap conflict. The end- of-week rebase produces a large, expensive conflict. Same underlying change shape, vastly different cost.

Prevention rule 4 — communication

The cheapest prevention is talking. When two engineers know they are both editing terraform/iam/main.tf, one can merge first or coordinate the changes. When they do not know, the conflict is a surprise:

  • A team channel or daily standup that surfaces “I am working on” notes lets engineers coordinate before starting.
  • CODEOWNERS (see below) routes PRs to the same reviewer, who can spot conflicts and serialise the changes.
  • File ownership (one engineer per directory) eliminates the case entirely.

Communication is not a Git feature; it is a team discipline. It is the prevention measure that requires no commands and produces the highest return.

Prevention rule 5 — file ownership via CODEOWNERS

For shared files, a CODEOWNERS file that names required reviewers per path reduces conflicts by routing both engineers to the same reviewer who can serialise the work:

# .github/CODEOWNERS
/terraform/iam/   @platform-security-team
/ansible/inventory/  @ops-team
/kubernetes/production/  @sre-team

When engineer A opens a PR touching /terraform/iam/main.tf, the platform-security team is required as a reviewer. When engineer B opens a parallel PR touching the same file, the platform-security team is again required. The reviewer sees both PRs and can either (a) sequence them so only one lands at a time, or (b) coordinate the merge. Conflicts on that file drop to zero without any change to the engineers’ behaviour.

The tooling layer — git rerere

git rerere (Reuse Recorded Resolution) is a Git feature that remembers how a conflict was resolved and replays the same resolution automatically when the same conflict recurs. It does not prevent conflicts, but it makes the cost of recurring conflicts near-zero:

# Enable rerere globally
git config --global rerere.enabled true

# Run a merge with rerere active
git merge feature/iam-rotation
# CONFLICT (content): Merge conflict in terraform/iam/main.tf

# Resolve the conflict in the editor...
# ... save the file ...
git add terraform/iam/main.tf
git rerere status
# Recorded resolution for terraform/iam/main.tf.

The resolution is recorded. When the same conflict arises later (say in a rebase, a cherry-pick, or another merge), git rerere detects that the index’s stage-1/stage-2/stage-3 blobs match a previously-recorded resolution and applies it automatically. The merge continues without manual intervention:

# A week later, the same conflict on a different branch
git merge feature/iam-rotation-rev2
# CONFLICT (content): Merge conflict in terraform/iam/main.tf
# Resolved 'terraform/iam/main.tf' using previous resolution.
git status
# All conflicts fixed but you are still merging.

The recorded resolutions live in .git/rr-cache/. They are local to the machine by default; rerere.enabled configured globally applies to all repositories for that user.

When prevention is itself the problem

Sometimes a high conflict rate is a sign of a deeper problem: the branches are scoped too broadly, the commits are too large, the team is too large for the file-set being shared, or the architecture has too many cross-cutting files. Prevention is a workflow fix; if the workflow is already correct and conflicts persist, the issue is architectural:

  • A shared “everything” file that many engineers must edit is a single point of contention. Splitting it (e.g. one IAM file per service) reduces cross-engineer edits.
  • A long-lived branch that has been alive for weeks is a sign that the work is not a feature but a project. Refactor the branch lifetime rather than the conflict resolution path.
  • A high-traffic shared directory with no ownership is a sign the team needs CODEOWNERS or split ownership.

The lesson: a merge conflict is information about the workflow. Reading that information is the deepest form of conflict prevention.

Production discipline

Three rules for an infrastructure repository that runs with few conflicts in production:

  1. Branch lifetime is a budget. A branch older than 24 hours is a workflow smell; a branch older than a week is a project smell. The shorter the branch lifetime, the lower the conflict probability.
  2. Enable rerere repository-wide. A pre-receive hook or a documented git config --global rerere.enabled true for every engineer is the cheapest conflict-cost reduction available.
  3. Read high-conflict files as architectural signals. When the same files show up in merge conflicts every week, the message is structural: split the file, concentrate ownership, or both. A merge conflict is rarely the only symptom of a workflow problem.

Cross-course references

  • Linux for Production Sysadmins — Part XXVIII (ChangeMgmt) covers change management as conflict prevention; the architectural analogue to branch lifetime is change-window size.
  • Ansible for Production Sysadmins — Part XXXVII (RepoArch) discusses inventory file ownership as the primary prevention for case-2 conflicts.
  • Terraform for Production Sysadmins — Part XIX (PR) and Part XX (State) recommend CODEOWNERS per-module for state isolation; the prevention layer is the same as for Git conflicts.

Quiz

Knowledge check · 4 questions

  1. Q1. What does `git rerere` do, and how is it enabled?

  2. Q2. Short-lived branches and small atomic commits are workflow choices, not Git features, and the conflict-rate reduction comes from how the team operates rather than from any configuration setting.

  3. Q3. Name two workflow measures and one tooling measure that together reduce both the rate and the cost of merge conflicts in an infrastructure repository.

  4. Q4. Diagnose a high-conflict-rate repository and recommend the workflow changes that will reduce the rate.

    An infrastructure team of twelve engineers maintains a single Terraform monorepo with 200+ `.tf` files and a single shared `terraform/iam/main.tf` that defines every IAM policy in the organisation. Every week, two to three PRs conflict on `terraform/iam/main.tf`. The branch lifetime is 3 to 14 days. No rerere is configured. No CODEOWNERS exists. The team lead asks what to change.

Passing score: 75%. Answers are checked in this browser.