Expand description
git-xcrypt diff — the textconv driver behind git diff on a secret.
Registered by init as diff.git-xcrypt.textconv. Git runs it with the path
of a file and reads its stdout as the text to compare, which makes this the
one place in the product where writing to stdout is the contract rather
than a corruption. The rule it looks like an exception to is narrower than it
sounds: on the filter path git treats stdout as the file itself, so a
stray byte damages a user’s file. Here stdout is a diff, never a file.
Four properties shape it.
It decides from the header, never from .git-xcrypt. The same rule the
smudge path follows, and it is not a stylistic choice here either: git hands
this command two different kinds of content under the same argument. For a
blob it writes a temporary file holding the stored bytes — ciphertext. For a
working-tree side, and for a blob whose working-tree copy is already
identical, git borrows the working-tree file itself rather than converting
it, so the argument is plaintext. Only the header can tell the two apart.
Content without our magic passes through untouched. That is the same
case, plus the one the plan names: a file committed before it was ever
declared. Failing on it would break git log -p across the whole history,
and the content is not a secret this command could protect anyway — it is
already in the object database in the clear.
The output is git-form, never working-tree form. The decrypting branch is
only reached when the smudge filter did not run first — a repository where
the diff driver is registered and the filter is not. Both sides of such a
diff arrive as ciphertext, so emitting the bytes that were fed to the cipher
keeps them comparable, and it makes the output a function of the blob alone
rather than of the machine’s core.autocrlf.
The key is fetched only when the content needs it. A clone with no key
can still run git log -p over history from before the repository was
configured, and git diff on an ordinary file never touches the key at all.