Repository navigation
hook install never registers the graph.json merge driver that README and CHANGELOG 0.7.0 both document #1902
Description
Summary
The README (twice) and CHANGELOG 0.7.0 state that graphify hook install configures a git merge driver for graphify-out/graph.json. It doesn't. hooks.install() writes only the post-commit and post-checkout scripts — it never writes .gitattributes and never registers merge.graphify in .git/config.
The graphify merge-driver subcommand itself is fine. Only the registration half is missing, so the fix looks small.
Docs that promise it
README.md (team setup):
Run
graphify hook installto auto-rebuild after each commit (AST only, no API cost). This also sets up a git merge driver sograph.jsonis never left with conflict markers — two devs committing in parallel get their graphs union-merged automatically.
README.md (troubleshooting):
graph.jsonhas conflict markers after two devs commit at once
Rungraphify hook install— it sets up a git merge driver that union-mergesgraph.jsonautomatically so conflicts never happen.
CHANGELOG.md 0.7.0:
Feat:
graphify hook installnow also configures a git merge driver forgraphify-out/graph.json… writes.gitattributesand registersgraphify merge-driverin.git/config
cli.py help text also says the driver is "set up via hook install".
Repro (v0.9.15)
cd "$(mktemp -d)" && git init -q
graphify hook install
# post-commit: installed at .../.git/hooks/post-commit
# post-checkout: installed at .../.git/hooks/post-checkout
git config --get-regexp '^merge\.' # -> nothing
ls .gitattributes # -> No such file or directoryExpected: merge.graphify.driver registered and graphify-out/graph.json merge=graphify in .gitattributes.
Actual: neither. The two hook scripts are the only side effects.
Code path
cli.py elif cmd == "hook": (~L336) → hooks.install() (hooks.py L507–542), whose entire body resolves the hooks dir, pins sys.executable into both scripts, then:
commit_msg = _install_hook(hooks_dir, "post-commit", hook, _HOOK_MARKER)
checkout_msg = _install_hook(hooks_dir, "post-checkout", checkout, _CHECKOUT_MARKER)
return f"post-commit: {commit_msg}\npost-checkout: {checkout_msg}"No merge-driver work anywhere in the function.
It doesn't appear to have regressed — it looks like it never shipped
Counting gitattributes|merge_driver|merge\.graphify|merge=graphify in each file at each tag:
| file | v0.7.0 | v0.8.0 | v0.9.0 | v0.9.15 |
|---|---|---|---|---|
graphify/hooks.py |
0 | 0 | 0 | 0 |
graphify/install.py |
0 | — | — | 0 |
graphify/cli.py |
0 | — | — | 0 |
graphify/__main__.py |
0 | — | — | 0 |
tests/test_hooks.py has 12 tests (test_install_creates_hook, test_install_idempotent, test_install_creates_post_checkout_hook, …) and zero reference merge. Nothing asserts the registration, which is consistent with the payload landing in 0.7.0 while the wiring didn't.
Impact
graphify-out/ is documented as something to commit, so this bites exactly the multi-dev workflow 0.7.0 was aimed at: two branches touching code both regenerate graph.json, and the merge leaves conflict markers in a large generated file nobody can hand-resolve. The troubleshooting entry for that symptom prescribes a command that doesn't fix it.
The driver works when wired by hand
Registering it manually and merging two branches that each add a distinct node union-merges cleanly, no conflict markers:
git config merge.graphify.name "graphify graph.json union merge"
git config merge.graphify.driver "$(command -v graphify) merge-driver %O %A %B"
printf 'graphify-out/graph.json merge=graphify\n' > .gitattributes
# branch A adds MarkWatched, branch B adds SyncQueue, then:
git merge feat-a
# -> nodes: ['Base', 'MarkWatched', 'SyncQueue']; no conflict markersSo merge-driver itself is good — hooks.install() just needs to register it.
Suggested fix
In hooks.install(), alongside the two _install_hook calls:
git config merge.graphify.name/merge.graphify.driverin the repo's.git/config.- Ensure
graphify-out/graph.json merge=graphifyin.gitattributes(append idempotently; it's a tracked file, so don't clobber).
One wrinkle worth considering: the driver command should probably be an absolute path, for the same reason the hook scripts already pin sys.executable. Git invokes the driver through a shell, and ~/.local/bin is routinely absent from PATH in GUI git clients and CI — the exact environments the pinning comment in install() calls out. A bare graphify merge-driver … would fail there and silently fall back to a conflicting merge.
If the intent is instead that users wire this themselves, the two README passages and the CHANGELOG entry need correcting — the troubleshooting one especially, since it's the answer given to someone already hitting the bug.
Found while setting this up on a fresh repo; happy to send a PR if the approach above looks right.
graphify 0.9.15 · macOS 15.5 (arm64) · Python 3.14 · uv tool install
Activity
chore: open 0.9.17 with 8 batch fixes (#1895 #1897 #1902 #1907 #1896 #…
Fix spurious hooksPath warning and register graph.json merge driver
Squashed commit of the following:
Fix spurious hooksPath warning and register graph.json merge driver
chore: open 0.9.17 with 8 batch fixes (Graphify-Labs#1895 Graphify-La…