Skip to content

emrg: the merge gate's own remedy creates symlinks that .gitignore's trailing-slash rules cannot ignore #1963

Closed

Description

@argszero

Measured on master c9d7f4b7.

The merge gate prints a remedy that creates two symlinks inside a worktree:

scripts/check-merge-plan-suite.py:
    node:   ln -sfn <main>/emrg/gui/node_modules <worktree>/emrg/gui/node_modules
            ln -sfn <main>/.venv <worktree>/.venv

.gitignore covers those two names with a trailing slash (lines 3-4: node_modules/, .venv/), and a trailing-slash pattern matches directories only. So the links the gate tells the operator to create are not ignored, and git add -A in that worktree stages them.

Measured, in a scratch repository carrying this repo's own rules

path node_modules/ (current) node_modules (no slash)
emrg/gui/node_modules as a directory ignored ignored
emrg/gui/node_modules as a regular file NOT ignored ignored
emrg/gui/node_modules as a symlink NOT ignored ignored

git status --porcelain prints ?? emrg/gui/node_modules for the last two, and git add -A stages them. Identical measurements for .venv (.venv/ → NOT ignored, .venv → ignored).

Why the regular-file row is the one to fix, not just the symlink

A symlink needs a privilege on some platforms; a plain file does not. Both are the same defect — the slashed rule matches one kind of thing and silently not the others — and the file form is what makes the gap testable everywhere. Symlinks are simply how it has actually been hit here: a cycle that links node_modules into a worktree to run the node suite and then runs git add -A commits the link, and the first symptom is a spurious red in a different test (the tracked-file scan reads the link's target as a file and reports emrg/gui/node_modules: could not be read as UTF-8 text ([Errno 21] Is a directory). That has cost two cycles of suite re-runs.

This file already applies the reasoning to another name

.gitignore's .emrg-* block records the same finding, for the same reason:

No trailing slash: .emrg-*/ matches directories only, so a stray file named .emrg-verify stayed untracked-but-unignored and could still be swept in by git add -A (#1119 review, how2how2how2-arch). .emrg-* covers both forms. Verified safe: git ls-files | grep '\.emrg-' is empty.

The same reasoning was not carried to node_modules/ and .venv/.

Remedy

  1. Drop the trailing slash on those two names, worded like the .emrg-* block that already states the rule. Safety measured the same way: git ls-files | grep -cE '(^|/)(node_modules|\.venv)$' → 0, so nothing tracked changes state.
  2. A guard that asks git rather than reading the file's text — a comment cannot enforce it, which is why tests/test_scratch_roots_are_gitignored.py and tests/test_patch_backups_are_gitignored.py exist. It must carry its own positive control: the same probe against the slashed rule has to come back "not ignored", or the assertion would pass on the broken file.

The remedy text the gate prints needs no change: once the names are un-slashed, the links it tells the operator to make are ignored.

Activity

  1. argszero commented on Oct 8, 2026

    @argszero
    OwnerAuthor

    Handled by #1964

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions