Fix textconv producing empty diffs on Linux (use cat instead of git-crypt diff)#332
Open
mischadiehm wants to merge 1 commit intoAGWA:masterfrom
Open
Fix textconv producing empty diffs on Linux (use cat instead of git-crypt diff)#332mischadiehm wants to merge 1 commit intoAGWA:masterfrom
cat instead of git-crypt diff)#332mischadiehm wants to merge 1 commit intoAGWA:masterfrom
Conversation
Git applies the smudge filter before invoking the diff textconv command, so encrypted blobs have already been decrypted by the time textconv runs. The textconv command only needs to pass that plaintext through to Git's diff machinery. Using cat avoids invoking git-crypt diff redundantly during diff generation.
There was a problem hiding this comment.
Pull request overview
This PR fixes empty diffs for git-crypt–encrypted files on Linux by adjusting the configured Git textconv command to avoid re-invoking git-crypt diff on content that Git has already decrypted via the smudge filter.
Changes:
- Update
configure_git_filters()to setdiff.*.textconvtocat(both default-key and named-key drivers). - Remove dependence on
git-crypt diffduring Git diff/log/blame operations, preventing the observed “empty diff” behavior on some Git/Linux combinations.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mischadiehm
added a commit
to narrowin/git-crypt
that referenced
this pull request
Apr 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On Linux with git 2.43 (and likely other recent versions),
git diffbetween two commits shows no output for encrypted files. The diff is completely empty — not "Binary files differ", just nothing.This makes
git log -p,git diff <commit> <commit>, andgit blameuseless for encrypted files on Linux. macOS is unaffected.Root cause
configure_git_filters()setsdiff.git-crypt.textconvtogit-crypt diff. But git applies the smudge filter (decrypt) to blob content before passing it to the textconv command. By the timegit-crypt diffreceives the file, it's already plaintext.After loading the repo key,
git-crypt diffsees no\0GITCRYPT\0header, hits the "not encrypted" path, and copies the content through unchanged. This makes the configured textconv a redundant identity transform that unnecessarily depends on git-crypt key loading, repo discovery, and header probing. On some git versions this redundant round-trip produces empty output instead of a plaintext diff.Verified by tracing the textconv invocation:
The temp file contains plaintext, not the encrypted blob.
Fix
Replace
git-crypt diffwithcatin both the named-key and default-key paths ofconfigure_git_filters():catis correct because:catjust passes the plaintext through to git's diff machinerycatis POSIX and avoids invoking git-crypt a second time during diffWhat about locked repos?
Under the normal lock/unlock flow, locked repos do not have this textconv configured:
git-crypt lockcallsdeconfigure_git_filters, which removes both the smudge filter and the diff textconv. So the supported path does not rely oncathandling encrypted content.Tested
Built the exact upstream PR branch commit on macOS Apple Silicon with Apple Git 2.50.1 and Homebrew OpenSSL 3:
Also built and tested the same commit in an Ubuntu 24.04.4 container with Git 2.43.0. The container copied the PR worktree, installed
g++ make libssl-dev git, builtgit-crypt, and ran the same focused checks below.Focused behavioral checks against the built binaries:
diff.git-crypt.textconvis configured ascatgit diff HEAD~1 HEAD -- secret.txtshows plaintext-original secret/+modified secretdiff.git-crypt-team.textconvis configured ascatgit-crypt lockremoves the diff textconv config;git-crypt unlock KEYFILErestores it ascatoriginal/modifiedbytes), not blobs beginning with\0GITCRYPT\0Also verified the fork's broader smoke test suite with the same textconv behavior:
Result: 12/12 tests passed, including the diff-driver test.
Existing users
Users who already have
git-cryptconfigured in a repo keep the oldtextconvsetting until they re-rungit-crypt unlock. This is expected —unlockcallsconfigure_git_filterswhich updates the config.Files changed
commands.cpp— two lines inconfigure_git_filters()