Skip to content

git diff --numstat dashes mean "no textual diff", not "binary", and three different decisions produce them #4164

Description

@louistrue

git diff --numstat prints - for added and - for deleted when it has NO TEXTUAL
DIFF for a path. Code that reads those dashes as "this file is binary" is reading a
decision as if it were a fact about the bytes.

There are three separate causes, and only ONE of them is about the content:

  1. A NUL byte in the first 8,000 bytes. This is the only one that says anything
    about what the file contains.
  2. A .gitattributes decision: -diff, binary, or a named diff driver. Someone
    configured it. The bytes are irrelevant.
  3. core.bigFileThreshold. A size cutoff, also a configuration decision.

Where this bites in this repo

Four tracked .ifc sample files are TEXT, and about twenty Rust and CLI tests read them
byte for byte. They report as binary to --numstat, so anything classifying paths by
that signal puts them in the inert or non-diffable bucket while the test suite is
parsing them as STEP.

That is the shape worth fixing regardless of any one consumer: a tool asked "did this
change" and got back "I chose not to tell you", and read the second as the first.

What to do

  • Pin the .gitattributes -diff case as a test, with one of the four real .ifc
    samples, so the classification cannot silently flip back.
  • Carry a comment at the read site recording that -/- means "no textual diff" and
    listing the three causes, since the meaning is not guessable from the output.
  • Anywhere the question is really "is this file text", ask that directly rather than
    inferring it from a diff tool's willingness to diff.

Provenance

Found by another session while working #4137. Its branch was closed in favour of #4140,
which is a simpler implementation that never consults git and so is immune to this hole.
That means the finding would have evaporated with the closed branch, which is why it is
recorded here rather than lost. The three causes above are that session's, verbatim in
substance.

Filed on their behalf so the knowledge outlives the branch. I am not claiming it.

Activity

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

    readyMaintainer-approved: in scope, wanted now, scoped. A PR may close this.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions