Home > OS >  git diff --ignore-matching-lines ignores all lines
git diff --ignore-matching-lines ignores all lines

Time:12-11

I'm trying to use git's --ignore-matching-lines, but running into some weird behavior. Here's the output of a plain git diff:

$ git diff test.txt
diff --git a/test.txt b/test.txt
index 602c47d1cb..82655814c5 100644
--- a/test.txt
    b/test.txt
@@ -1,5  1,7 @@
-Hello world
 Hello whitespace world
 
 
 Lots of blank lines
 
 Goodbye world
 

However, if I run

$ git diff --ignore-matching-lines='^$' test.txt

I get no output

Why is this ignoring the change that adds the word whitespace?

CodePudding user response:

This could be caused by how '$' itself is interpreted, as detailed in "How does git diff --ignore-matching-lines work", by Sjoerd Langkemper (also a Stack Overflow user):

Git runs each regex over each line.
These lines end in a newline, so our regex is actually checked against:

His bill will hold more than his belican,\n

Where \n stands for a newline character.

When we have a change that adds an empty line, the regex is ran against a single byte string consisting of \n.
How do we match that?

It’s easier to use something like --ignore-blank-lines to ignore blank lines.

(Check, by the way, if git diff --ignore-blank-line is a good option in your particular case)

However, this does not work well together with other regular expressions that we want to ignore.
If we want to ignore a change that performs both an uninteresting belly-related change and adds an uninteresting empty line, our regular expressions we give to -I need to match both for the change to be hidden.
So we need a regular expression that matches an empty line, and --ignore-blank-lines and other white space related options don’t change that.

An empty line cannot be matched with ^$.

  • ^ matches both the beginning of the line and the beginning of the buffer.
  • Similarly, $ matches both the end of the line as the end of the buffer.

All changed lines end in a newline, just before the end of the buffer.
This means that ^$ matches every changed line.
The newline at the end starts a new line, and is immediately followed by the end of the buffer.

… his belican,\n
               ↑
               ^ matches because \n starts a new line
               $ matches because the buffer ends here

That would explain why a --ignore-matching-lines='^$' is ignoring the change that adds the word whitespace: it is ignoring all the lines!

To match more precisely, we can use \` to match the start of the buffer, and \' to match the end of the buffer.
An empty line can thus be matched with:

 \`\n\'

Where \n is an actual newline, not backslash-n.
This needs much escaping to enter correctly in a shell:

git diff -I $'\\`\n\\\'' …
  • Related