Rendered from docs/interfaces/headwater-merge-driver.md in the Headwater
corpus. Every document on this half of the site is typed by the taxonomy
the descriptor names: corpus.json.
headwater merge-driver
Synopsis
headwater merge-driver <ancestor> <current> <other> <path>
Git runs the verb, and a person does not. The configuration names it as headwater merge-driver %O %A %B %P, and headwater init --git prints that configuration.
Description
A derived artifact that holds a fold states one value over the whole corpus. Two branches that each move the fold write two values. A three-way merge of the two gives a value that is true of neither tree. HW-DR-0049 rules that such a file is rebuilt after a merge and never reconciled.
A clone gives each such path merge=headwater-regenerate in its own info/attributes, and git then calls this verb for the path. The committed .gitattributes gives the path -merge, which conflicts with no driver. The verb does three things:
- It leaves the current side (
%A) byte for byte. Git reads the merge result from that file. - It writes to standard error the path and the command that rebuilds it. The command is
headwater taxonomy resolvefor.headwater/taxonomy.lockandheadwater generatefor every other path. - It exits 1, so git records the path as conflicted.
Git writes no conflict marker for a custom driver. So the file stays readable, and the resolution is one deterministic step: finish the merge, run the command, and stage the result. Every generated file records the digest of the lock. So when the lock is conflicted too, run headwater taxonomy resolve before headwater generate.
The verb does not rebuild the file, although the driver name says "regenerate". Git runs a driver during the merge, one path at a time. At that moment the other paths of the tree are not all merged. A fold that is rebuilt then describes a tree that never existed, and it looks correct. So the verb names the producer and does not run it.
The verb does not break the rule of spec 5 that no hook introduces a verb. HW-DR-0077 gives the reason. That rule forbids a second entry point to route or to check. This verb answers a question that no other verb answers, which is what a merge does with a derived fold.
What the driver cannot reach
Git calls no driver when the two branches wrote the same bytes. A driver is a content merge. Git compares the two blobs first, and it resolves a path that has one blob at the tree level. Two branches that each add one document of one kind can write one identical fold. That merge gives a value true of neither tree, and git does not call this verb. engine/crates/census/tests/merge_driver.rs measures this case.
Git calls no driver in a clone that has the configuration and not the override. Git runs no hook before a merge, so nothing can write the override between the git config lines and a first merge. That merge keeps the current side of each fold and conflicts, and no message names the producer. Anything else that the driver does for a repository is also absent from that merge. A repository that writes a review marker from its driver gets no marker. headwater init --git in a configured clone writes the override, and it is the step to run before the first merge.
A forge calls no driver, and it does not read -merge. We measured this on GitHub on 2026-09-24. A pull request that moved a -merge path showed as mergeable, and its test merge held the edits of both branches.
The check on the merged tree is what reaches these cases, and the driver is its fallback. headwater generate --check and headwater taxonomy resolve --check are that check. An adopter runs them after a merge and in CI. This repository also runs them from a commit hook while a merge is in progress. No verb carries that hook, because HW-DR-0077 gives its exception to the driver alone, and a second verb for a hook needs its own ruling.
Preconditions
Git must find headwater on the PATH that it runs with. The verb reads no corpus and no lock, so it runs on a tree in the middle of a merge.
Git calls the verb only for a path whose attribute is merge=headwater-regenerate, in a clone whose configuration names the driver. A clone without the configuration reads the driver as an ordinary text merge. So the attribute goes in the info/attributes of the clone and never in .gitattributes. headwater init --git commits -merge and prints the configuration and override lines. headwater init --git --git-config also writes them.
Options
| Option | What it does |
|---|---|
<ancestor> |
The file that holds the version of the common ancestor, %O. The verb does not read it. |
<current> |
The file that holds the version of the current side, %A. The verb does not change it. |
<other> |
The file that holds the version of the other side, %B. The verb does not read it. |
<path> |
The path of the artifact in the tree, %P. It selects the command that the message names. |
--root <path> |
Accepted and not read. The verb reads no corpus. |
--no-color |
Force plain text on both streams: bold and dim weight plus glyphs, no escape sequence. The default already senses whether each stream is a terminal, and renders color only there. |
--no-banner |
Suppress the masthead: the line naming this binary and its version, that the root help screen alone prints. It is accepted here and does nothing, since only the root screen prints one. |
Exit status
1 means that the path is left conflicted with the current side in place. Git reads it as a conflict. It is the only status that the verb gives. A call with fewer than four operands also exits 1, and it names the form that git uses. Git always supplies all four.
1, and never 101, when standard output or standard error cannot be written, and one sentence on standard error names a failed standard output.
Environment
No environment variable reaches this verb. Git finds the binary through PATH, and the verb reads nothing from its environment.
Files
| Path | How this verb treats it |
|---|---|
info/attributes in the git directory |
Not read by the verb. Git reads it, and a merge=headwater-regenerate line there is what makes git call the verb. |
The <current> file |
Left byte for byte. Git reads the merge result from it. |
The <ancestor> and <other> files |
Not read. |
.headwater/taxonomy.lock |
Named in the message, with headwater taxonomy resolve, when it is the <path>. |
Any other <path> |
Named in the message, with headwater generate. |
The verb writes no file, and nothing on standard output, because standard output during a merge belongs to git.
See also
headwater init writes the .gitattributes lines, and prints the configuration and override that select this verb.
headwater derived computes which files a producer writes, and it reports a producer output that carries neither -merge nor merge=headwater-regenerate.
HW-DR-0049 rules that a fold is derived and never stored. HW-DR-0077 rules that merge safety ships as this verb.
Spec 6 lists the command line.