Skip to content

hook install never registers the graph.json merge driver that README and CHANGELOG 0.7.0 both document #1902

Closed

Description

@luizbon

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 install to auto-rebuild after each commit (AST only, no API cost). This also sets up a git merge driver so graph.json is never left with conflict markers — two devs committing in parallel get their graphs union-merged automatically.

README.md (troubleshooting):

graph.json has conflict markers after two devs commit at once
Run graphify hook install — it sets up a git merge driver that union-merges graph.json automatically so conflicts never happen.

CHANGELOG.md 0.7.0:

Feat: graphify hook install now also configures a git merge driver for graphify-out/graph.json … writes .gitattributes and registers graphify merge-driver in .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 directory

Expected: 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 markers

So merge-driver itself is good — hooks.install() just needs to register it.

Suggested fix

In hooks.install(), alongside the two _install_hook calls:

  1. git config merge.graphify.name / merge.graphify.driver in the repo's .git/config.
  2. Ensure graphify-out/graph.json merge=graphify in .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

  1. added a commit that references this issue on Jul 15, 2026
    f2a6139
  2. added a commit that references this issue on Jul 16, 2026
  3. added 2 commits that reference this issue on Aug 13, 2026
    f23e02f
    6453909
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions