Reputation: 4484
I have a git repo, where I replaced a lot of files locally.
git status now shows many many modified files.
Some are "really modified", others only differ by line endings.
I want the ones that differ only by line endings to go away (git reset them), but I cannot seem to find the linux-piping-foo to make it happen.
Bonus points for how to remove files whose only difference is the executable bit.
Upvotes: 47
Views: 13202
Reputation: 1261
If your changes are not staged
To stage changes that are not just whitespace changes, you can do:
git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -
Afterwards, to remove all unstaged changes (those changes that differ only in whitespace), you can do:
git checkout . (or, in newer gits, git restore .)
If your changes are staged
Unstage your changes by doing a git reset --mixed
and continue from the top of this answer. Note that mixed is the default mode and can be omitted.
Upvotes: 0
Reputation: 26406
cd /mnt/c
.cd repos/my-project
git diff -b --numstat \
| egrep $'^0\t0\t' \
| cut -d$'\t' -f3- \
| xargs git checkout HEAD --
Upvotes: 3
Reputation: 3467
If you're allergic to bash and prefer powershell (formatting for clarity)...
git diff --numstat --ignore-space-change --ignore-all-space
--ignore-blank-lines --ignore-cr-at-eol
--ignore-space-at-eol
| % {($added,$deleted,$path)= $_.Split("`t");
if ("$added$deleted" -eq "00") {$path}
| % { git checkout HEAD $_}
Note that this is a pretty aggressive approach - the git options I've used here will also ignore added/deleted blank lines. Also remember that whitespace and even line-feeds can be semantically meaningful when in the middle of a string so use with that in mind.
It's possible that some of the git options are redundant but I've included them for paranoia's sake. You may wish to peruse the documentation to form your own interpretation.
Here's a slightly terser implementation for cutting and pasting...
git diff --numstat -b -w --ignore-blank-lines --ignore-cr-at-eol --ignore-space-at-eol | % {($a,$d,$p)= $_.Split("`t");if ("$a$d" -eq "00") {$p}| % { git checkout HEAD -- $_}
As was noted elsewhere, it may be advisable to take a copy of your changes before reverting by running git stash
or copying to a backup folder first.
Upvotes: 1
Reputation: 733
Though it seems you were originally looking for a pipe-based solution and you got it from @aristotle-pagaltzis, since it's a bit hard to remember, I think this alternative is worth noting:
git diff -b > gitdiffb
git stash # or git reset --hard if you feel confident
git apply --ignore-space-change gitdiffb
If not just changes to whitespace numbers, but also whitespaces that are completely new or completely removed should be ignored, replace -b
by -w
.
The outcome differs from the pipe-based solution in the removal of whitespace changes even in files that also contain relevant changes. Thus, it's not exactly the way you described it, but for most people coming here via a search engine are probably rather looking for this.
Upvotes: 19
Reputation: 117959
This will do it:
git diff -b --numstat \
| egrep $'^0\t0\t' \
| cut -d$'\t' -f3- \
| xargs git checkout HEAD --
diff -b
.git checkout
against the branch tip.This pipe will do something sensible for each step you leave off, so you can start off with the just the first line and add more to see what happens at each step.
A possibly useful alternative last line:
| git checkout-index --stdin
This would reset the files to their staged contents instead of to their last committed state.
You may also want to use git diff HEAD
on the first line instead, to get a diff of the working copy against the last commit instead of against the index.
Note: if you have filenames with spaces in them, you will first need to add a tr
:
git diff -b --numstat \
| egrep $'^0\t0\t' \
| cut -d$'\t' -f3- \
| tr '\n' '\0' \
Then you must add a -0
/-z
switch to whichever final command you wanted to use:
| xargs -0 git checkout HEAD --
# or
| git checkout-index --stdin -z
Upvotes: 50