--- name: merge description: "Resolve an in-progress merge or rebase by the intent of both sides, re-run the full gate on the merged tree, and finish the operation." category: delivery mutates: repo --- # Merge A conflict is two intents meeting, not two texts disagreeing. Resolve it by understanding what each side was for. Always resolve; abandoning the operation returns the same conflict to the next person with less context than you have now. ## See the state Establish what is actually in progress before touching a file: ```bash git status git log --oneline --left-right --boundary HEAD...MERGE_HEAD mapfile -t conflicted < <(git diff --name-only --diff-filter=U) printf '%s\n' "${conflicted[@]}" ``` Record that list while the paths are still conflicted: once the markers are gone the same query returns nothing, and this is the list you stage at the end. A rebase and a merge present the sides in opposite orders, so confirm which operation you are in before reading any hunk. During a rebase the side labelled as yours is the upstream branch, and the side labelled as theirs is the commit being replayed. ## Find the intent For each conflicting file, find the primary source of both changes: ```bash git log -p --follow -- ``` Read the commit messages, and where a commit points at a pull request or an issue, read that too. The wish that owns the work is the strongest source available in this repository: the criteria and the execution strategy say what the change was for in the author's own words. Keep reading until you can state each side's intent in one sentence. ## Resolve each hunk - Preserve both intents where they compose. Most conflicts are two independent edits that a mechanical tool could not interleave. - Where they genuinely cannot compose, keep the one matching the stated goal of this merge and note the trade-off in your report. - Never resolve by taking one side wholesale. Choosing a side without reading the hunk discards the other intent silently, which is exactly the failure a conflict exists to prevent. - Never invent behaviour neither side asked for. A conflict is not an opportunity to refactor. - Delete every conflict marker, then read the merged region as though it arrived as a fresh diff. It has to make sense on its own. ## Re-run the gate The merged tree is code neither side ever compiled. Run the repository's own full gate on it: the full aggregate check the repository defines, the one its CI enforces, not a hook's faster subset. That is `bun run check` in genie, and often `npm run check` or `make check` elsewhere. Find it in the repository's root scripts or task file and confirm it against what CI runs, rather than assuming one or taking a hook's command. That gate is the only proof the merge is sound. A green gate on either parent proves nothing about the merge. Fix what the merge broke, and re-run until it exits zero; a partial re-run proves only the part you re-ran. ## Finish Stage the paths you recorded as conflicted, nothing else, and complete the operation: ```bash git add -- "${conflicted[@]}" git commit -m 'chore: merge into ' git rebase --continue # when rebasing, until every commit is replayed ``` The subject uses a conventional-commit type. There is no merge type in the accepted set, so a subject beginning with that word alone is rejected by the commit hook; `chore` is the type that carries an integration commit. A rebase surfaces its conflicts one commit at a time, so run the gate again after the last commit replays, not only after the first resolution. ## Report Name each conflicting file, the intent you preserved on each side, every trade-off you took where the two could not compose, and the gate result on the merged tree with its exit status.