Reputation: 1755
I performed a sed search/replace on a large codebase, and for every file that sed passed over, it added a newline at the end if none was there previously. While it is good convention to end the last line with \n, this is a huge diff that is irrelevant to what I was trying to accomplish. The change affected hundreds of files, which I don't want to manually check and git checkout
by hand.
Is there any way to selectively add or remove staged changes such that files that have only "no newline at end of file" will be ignored?
Upvotes: 9
Views: 4278
Reputation: 5333
What I did differs a bit from @BenMorris's solution, which finds files that only have the whitespace difference and no other changes. I wanted to discard the EOF newline change even if there are other valid changes in the same file:
To get a list of files with such differences:
git diff | grep '\(+++\|No newline at\)' | grep -B 1 'No newline at'
...or if your grep supports it, this will clean up the output to give just the paths:
git diff | grep '\(+++\|No newline at\)' | grep -B 1 'No newline at' | grep --perl-regexp -o '\+\+\+ b/\K.*'
That's enough to just point you to which files to clean up manually, but to automate the rest of the process....
Download and install splitpatch.rb if you don't have it
Make a complete patch of all staged changes in all files with EOF newline changes. (This includes a couple of grep -v's to avoid small issues with compatibility between git and the output of splitpatch.)
git diff --cached | grep '\(+++\|No newline at\)' | grep -B 1 'No newline at' | grep -Po '\+\+\+ b/\K.*' | xargs git diff --cached | grep -v "^diff --git a" | grep -v "^index " > fullpatch.patch
Break it up into hunks:
/path/to/splitpatch.rb --hunk fullpatch.patch
This creates separate numbered files named Filename.extention.00#.patch, starting from 000. Apply, in reverse, only the last (highest-numbered) patch for each source file (The line below is bash-only, not zsh, due to a difference in globbing):
for f0 in *.000.patch; do (for f_all in ${f0/000/*}; do echo $f_all; done) | tail -n -1; done | xargs -n 1 git apply —reverse
It's not impossible there could be a "real" change caught in the same hunk with the EOF newline, so take a look with git diff
and use an editor to undo any changes besides the last line.
Clean up:
ls *.patch
rm *.patch
When you add these small reverse changes to the index, you will have discarded the newline changes at EOF.
Upvotes: 0
Reputation: 1755
From the linked related issue, I found that git diff --ignore-all-space
would ignore files with only whitespace changes. git diff --ignore-all-space --name-only
doesn't work as I expected it to, but this does:
git diff --ignore-all-space | grep "+++"
This gave me a list of files that have changes other than whitespace, which is small enough that I can just add them all manually to the stage and commit.
Thanks to everyone for the comments, they were very helpful.
Upvotes: 6