mdsmith
Esc
    v0.52.0 GitHub

    mdsmith merge-driver

    Git merge driver that resolves conflicts inside generated sections.

    Register and run a Git merge driver. It auto-resolves conflicts inside generated sections — <?catalog?>, <?include?>, <?toc?>. The driver strips conflict markers in those blocks and runs mdsmith fix to regenerate them. It exits non-zero if any unresolved conflict markers remain.

    mdsmith merge-driver <subcommand> [args]

    # Subcommands

    # install [globs...]

    Register the merge driver in git config and ensure .gitattributes assigns it. The managed block uses globs derived from .mdsmith.yml: include patterns (default *.md and *.markdown) followed by an -merge exclude line for each representable ignore: pattern (last-match wins). ignore: entries that cannot be expressed in .gitattributes! negation patterns and patterns containing whitespace — are skipped, so the hook’s scope may include files the merge driver isn’t registered for.

    Optional positional args replace the default include set when scoping to a custom pattern (e.g. docs/**/*.md). Custom include globs are not compatible with MDS048 git-hook-sync auto-fix, which restores the canonical default set; do not enable git-hook-sync if you rely on custom includes.

    # ci-install

    Like install, but it treats the committed .gitattributes as the source of truth instead of rewriting it. This is the npm ci analogue of install’s npm install. It first checks the committed managed block against the globs derived from .mdsmith.yml. It never writes the file. It exits non-zero when .gitattributes is missing, has no managed block, or has drifted.

    Only after that check passes does it register the merge driver in git config and install the pre-merge-commit hook. Both are git-internal and untracked. A failed verification exits before either, so a drift error leaves the repository in place.

    Run it in CI and the merge queue. There, install would re-render .gitattributes mid-run. A drifted committed copy would be rewritten, which dirties the worktree. That aborts the in-progress git merge, requeues the PR, and re-fires the labeled trigger forever. ci-install never writes the tracked file. The merge starts from a clean tree, and real drift fails one setup step loudly instead of looping.

    ci-install takes no glob arguments. It always compares against the canonical default include set. So it is incompatible with custom-glob installs, the same as MDS048.

    # run <base> <ours> <theirs> <pathname>

    Driver entrypoint, invoked by Git. Not normally called by hand. After install or ci-install, Git will dispatch to it whenever merging a file marked merge=mdsmith.

    The driver writes only the <ours> temp file (%A). It regenerates sections by running mdsmith fix on the merged content in memory, anchored at <pathname> so neighbour files resolve as they would for the real file. The worktree path itself is never read or written. The driver runs while the parent merge is still in flight, so a worktree write changes the file’s stat data — even when the bytes are restored exactly. Git then treats the path as locally modified and aborts the merge (“Your local changes … would be overwritten”). Under git rebase, a pick that hits this is rescheduled forever.

    # Git config (set by install / ci-install)

    merge.mdsmith.driver = '/abs/path/to/mdsmith' merge-driver run %O %A %B %P

    The path is the absolute location of the mdsmith binary at install time, shell-quoted so paths with spaces work.

    # Examples

    mdsmith merge-driver install
    mdsmith merge-driver install 'docs/**/*.md'
    mdsmith merge-driver ci-install   # CI / merge queue: verify, don't write

    After install, a merge with conflicts inside a generated section auto-resolves. After conflicts in hand-written prose, run mdsmith fix <file> once the rest of the merge is resolved.