The conflicting files are derived output from a generator: resolve their source, re-run it and stage the fresh result rather than hand merging the output.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add wan-huiyan/agent-traffic-control --skill merge-conflict-generated-files --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Merge Conflict Generated Files?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/wan-huiyan-merge-conflict-generated-files)More formats (shields.io, HTML) on the badges page.
---
name: merge-conflict-generated-files
listing_tier: name-led
description: |
The conflicting files are derived output from a generator: resolve their source, re-run it and
stage the fresh result rather than hand merging the output.
author: Claude Code
version: 1.1.0
date: 2026-04-30
---
# Merge Conflict in Generated Output Files
## Problem
A project generates output files (HTML, JSON, CSS, TypeScript declarations, OpenAPI specs,
etc.) from a source-of-truth input. Both branches modified the source AND committed fresh
generated outputs. The merge/rebase now shows conflicts in the generated files — but hand-
merging them is both futile (the generator will overwrite them) and error-prone (computed
totals, sorted indexes, and aggregated summaries can't be correctly resolved by text diffing).
**The key mistake to avoid:** treating generated file conflicts as real conflicts requiring
line-by-line resolution. They're not — they're a side effect of forgetting that the files
are derived.
## Context / Trigger Conditions
Apply this skill when ALL of these hold:
1. Multiple files are in the conflict set, but most of them look like generated output (HTML
tables, JSON indexes, minified CSS, declaration files, changelogs built from commits).
2. You can identify a single source generator that produces them — a build command, a Python
script, `make docs`, `npm run build`, `openapi-generator`, etc.
3. `git diff --name-only origin/main...HEAD` shows the same generator SOURCE (not output) was
also modified on your branch, meaning both sides touched the source AND re-ran the generator.
4. Hand-merging the outputs would produce semantically wrong results (e.g., duplicate tracker
entries, stale totals, mismatched sort order, broken JSON).
**If only condition 4 holds — the conflicting thing is one derived NUMBER inside a file a
human wrote** (a stated test count, a coverage percentage, a totals row) — conditions 1–3 all
fail: the conflicting file is hand-authored rather than generated output; nobody generates it;
and there is no generator source for either side to have modified. The reasoning still holds
and the remedy is different, because there is no
generator to re-run. Skip to *Variant — the derived thing is a VALUE inside a hand-authored
file*, below.
**Common generator → output patterns:**
| Generator source | Generated outputs |
|---|---|
| Tracker/roadmap Python script | `docs/site/*.html`, `dist/roadmap.html` |
| OpenAPI YAML spec | `openapi.json`, `client/api/*.ts` |
| Sphinx `.rst` / `.md` | `docs/_build/html/**` |
| Docusaurus `sidebars.js` | `.docusaurus/`, `build/**` |
| `CHANGELOG.md` source blocks | `CHANGELOG.html`, release notes |
| Tailwind config | `dist/styles.css` (if committed) |
| `package.json` scripts | `dist/*.js`, `*.d.ts` (if committed) |
| ADR index script | `docs/decisions/index.md` |
## Solution
### Step 1 — Identify the generator and its output files
```bash
# Look for "generated" header comments in the conflicting files
head -3 <conflicting-file> # often says "# DO NOT EDIT — generated by ..."
# Look for generator scripts near the source files
ls docs/ # generate_*.py, build_*.sh?
cat Makefile | grep -A2 "html\|docs\|site"
# Check if output files are in .gitignore (they shouldn't be, if committed)
git check-ignore -v <conflicting-file>
```
### Step 2 — Classify each conflicting file
For each file in the conflict set:
| File type | Action |
|---|---|
| **Generator source** (Python/JS/YAML input) | **Hand-resolve** this one carefully — it's the real conflict |
| **Generated outputs** (HTML/JSON/CSS derived from source) | Take either side (doesn't matter — you'll overwrite) |
| **Add/add: same filename, different content** | Read both; keep the richer/more complete version, OR keep both under different names if they represent genuinely different artifacts |
| **Human-authored docs** (README, handoffs, analysis) | Hand-merge normally |
### Step 3 — Resolve the generator source
The generator source (e.g., the Python tracker script, the OpenAPI YAML, the Sphinx `.rst`)
is the ONLY file where the conflict is real. Resolve it carefully:
- **Union semantics** (append-only registers like tracker entries, ADR lists, lessons):
Keep ALL entries from both sides. Order chronologically. For the same entry ID with
different content on each side, keep **whichever version is more complete/recent** —
this is often the main branch's version if a later PR updated it after your branch diverged.
- **Merge semantics** (config files, schemas, structured data):
Resolve like any other content conflict — pick the semantically correct combination.
```bash
# After manually editing the source to have both sides' content:
git add <generator-source-file>
```
### Step 4 — Discard the generated output conflicts (take any side)
```bash
# During a merge (merging main INTO branch):
git checkout --theirs -- <generated-output-1> <generated-output-2>
# or --ours, it doesn't matter — you'll regenerate in the next step
# During a rebase (replaying branch ONTO main):
# WARNING: --ours/--theirs are REVERSED in rebase!
# In rebase: --ours = upstream (main), --theirs = your branch being replayed
# Still doesn't matter for generated files — just pick one side
git checkout --ours -- <generated-output-1> <generated-output-2>
git add <generated-output-1> <generated-output-2>
```
### Step 5 — Run the generator to produce correct output
```bash
# Run whatever command produces the output files
python3 docs/generate_website.py
# or: npm run build:docs
# or: make html
# or: openapi-generator generate ...
# or: sphinx-build docs/ docs/_build/
# The fresh outputs will replace the conflict-resolved stubs you staged in Step 4
git add <generated-output-1> <generated-output-2>
```
### Step 6 — Verify and commit
```bash
# Confirm no conflict markers anywhere
grep -rn "<<<<<<\|>>>>>>>\|=======" <generated-output-files>
# Spot-check the output: does it contain BOTH branches' contributions?
# (e.g., does the HTML contain both tracker entries? Does the JSON contain all entries?)
git status # should show "All conflicts fixed but you are still merging" (if merge)
# or let you continue the rebase
git commit -m "merge: resolve generated-file conflicts + regen from unified source"
# or: git rebase --continue
```
## Verification
1. No `<<<<<<` / `=======` / `>>>>>>>` markers remain in any file.
2. Running the generator again produces no changes (`git diff` is clean after regen).
3. The generated output contains contributions from BOTH branches (not just one side).
4. Any computed aggregates (counts, totals, sort orders) are correct in the fresh output.
## Example — Tracker + site regen
A Python script `docs/generate_tracker.py` produces `docs/site/index.html` and
`docs/site/roadmap.html`. Branch A added `Item("id-101", ...)` to the script and committed
fresh HTML. Branch B (main) added `Item("id-102", ...)` and also committed fresh HTML.
When Branch A merges main:
- `docs/generate_tracker.py` — real conflict → hand-union both Item() entries
- `docs/site/index.html` — generated → `git checkout --theirs -- docs/site/index.html`
- `docs/site/roadmap.html` — generated → `git checkout --theirs -- docs/site/roadmap.html`
- Run `python3 docs/generate_tracker.py`
- Verify `index.html` now contains both `id-101` AND `id-102`
- Commit
## Variant — the derived thing is a VALUE inside a hand-authored file
Everything above assumes a generator you can re-run. **The same insight applies one level
down, to a single derived NUMBER embedded in a file a human wrote** — and that is exactly
the case trigger condition 2 excludes, so without this section a model in a stacked rebase
never loads this skill at all.
The usual shapes: a README gate table row stating how many tests a suite collects
(`pytest docs` → N), a coverage percentage in a badge line, an "N skills" / "N endpoints"
figure in an intro paragraph, a row count in a data dictionary. Nothing generates these.
Whoever last measured typed them in by hand.
### Why every resolution of that conflict is wrong
In a stack of PRs where each one adds tests and each one edits the same counted line,
**the correct merged value exists on NEITHER side of the conflict**:
- *Your side* is your branch's base plus your own tests.
- *Their side* is main plus everybody else's tests.
- *The merged tree* is the base plus yours plus theirs — a third number nobody has measured.
Measured across three PRs in one stack (the routing app, 2026-08-07):
| PR | The rebase resolved the line to | What the merged tree actually collects |
|---|---|---|
| #780 | 459 | **461** |
| #807 | 461 | **476** |
| #781 | 476 | **480** |
Three resolutions, three wrong — and each looked perfectly reasonable when it was made,
because each side of the conflict was a real count of a real tree.
### Resolve to a placeholder, then measure once
```bash
# 1. During the rebase, put a literal that CANNOT be mistaken for a measurement:
# | `pytest docs` | **PENDING-REMEASURE** collected |
$EDITOR README.md
git add README.md
git rebase --continue
# 2. AFTER the rebase completes — not between two --continue steps, which would measure a
# tree that exists only mid-replay — measure the final tree, once:
pytest docs -q --co 2>&1 | tail -1
# 3. Put that number in, then prove no placeholder survived:
grep -rn "PENDING-REMEASURE" . # must be empty before you push
```
**Why a placeholder and not "take the more recent side":** a half-plausible number survives
by inertia. Nobody re-checks a value that already looks like a value, so a
wrong-but-reasonable count ships and then gets copied into the next document.
`**PENDING-REMEASURE**` cannot ship quietly — it fails a grep, a reviewer's eye, and often
the repo's own doc gate.
**And "bigger is newer" is not a tiebreak, because the count can go DOWN.** A later PR in
the same repo was rebased four times and the row went **530 → 559 → 516**, while the merged
tree collected **517**. Tests get deleted, renamed, and moved between suites; monotonic
growth is an assumption, not a property of the number.
## Notes
- **"Take either side" for generated files is intentional** — both sides are equally wrong
(each only has one branch's source baked in). The correct output comes from running the
generator on the merged source.
- **Same-named artifact (add/add)** — two branches independently wrote the same output
filename (e.g., `session_114_prompt.md`, `CHANGELOG.v2.md`) but for different purposes.
These are NOT generated files — they're real content. Rename the later-discovered one
rather than overwriting; both files represent distinct artifacts. Pre-detect with:
`git ls-tree origin/main -- path/to/filename` before committing.
- **Rebase --ours/--theirs reversal** — in a `git rebase`, `--ours` means the upstream
(main), not your branch. Always verify with `git diff --cached <file> | head -5` to
confirm you got the right side before staging.
- **If the generator is unavailable** (e.g., requires a runtime you don't have locally),
take main's side for ALL generated outputs — they're at least internally consistent —
then add a commit note that they need regen.
## See Also
- `synthetic-id-collision-rebase` — when the conflict isn't about content but about two
branches claiming the same synthetic ID (tracker IDs, ADR numbers, migration filenames)
- `pr-conflict-from-mid-flight-merges` — broader recipe for identifying and clearing all
mid-flight conflicts across a stale PR
- `overnight-multi-issue-implementation` (its own plugin in the `wan-huiyan-overnight-workflows` marketplace, not here)
([overnight-workflows](https://github.com/wan-huiyan/overnight-workflows)) — carries the
sibling rule for where a stated number comes from in the first place ("the rule survives;
the numbers do not — measure the baseline yourself, never carry a count from a document").
It says nothing about how to get through the conflict, which is what the variant above adds.
## Reference-only siblings in this toolkit
These carry `disable-model-invocation: true`. They never appear in the skill
listing and the Skill tool refuses them, so the only way in is to open the file
with Read when one of these matches what you are looking at.
- [`git-rebase-stalls-async-post-commit-hook`](../git-rebase-stalls-async-post-commit-hook/SKILL.md) — a multi-commit rebase stalls mid-replay in a repo with a background post-commit hook
- [`git-add-u-after-async-post-commit-hook`](../git-add-u-after-async-post-commit-hook/SKILL.md) — `git add -u` plus `--amend` plus force-push rolls thousands of unrelated deletions into your commit
- [`git-amend-hits-async-post-commit-hook-commit`](../git-amend-hits-async-post-commit-hook-commit/SKILL.md) — `git commit --amend` silently rewrote the hook's commit instead of yours
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!