Git Grep color options explained and/or compared

Solution 1:

Here's what the linked documentation says, trimmed a bit to make it all work out better:

context

     non-matching text in context lines (when using -A, -B, or -C)

matchContext

     matching text in context lines

matchSelected

     matching text in selected lines

selected

     non-matching text in selected lines

(I've left out match; we'll put that back in a moment). Let's say we run git grep findme, just so we have a search word.

The three technical terms, such as they are, here are:

  • matching text: This should be pretty obvious. We're searching for the literal string findme so this is each occurrence of that string. Color-coding the match is not as necessary for these kinds of fixed strings as it is for patterns: if we were searching for a pattern, it might be particularly useful to see just what the pattern matched.

  • context lines: The clue here is the mention of the three flags. You can get "before" context (-B), "after" context (-A), or both (-C), which basically means that if you are searching for findme and Git finds that, it will print out not just the line with the word findme in it, but also some lines before and after that line.

    Note that these before-and/or-after lines might not have findme in them—but then again, they might!

  • selected lines: Git kind of hides what this means, but building on the above, it's fairly guess-able: we were searching for the word findme and it occurred in some line(s). So those lines are selected, which distinguishes them from any context lines that did not have findme in them; those lines are not selected. (But see below!)

Here's an example, in searching for the word or. Git will color or in red, and otherwise do no coloring, by default, so I ran:

git -c color.grep.selected=green grep -C 2 -n or

which adds line numbers as well as using selected=green. Unfortunately I can't get StackOverflow to color code this for me, so instead I'll use bold where Git uses green, and italics where it uses red:

pfod.py-11-
pfod.py-12-This is basically a hybrid of a class and an OrderedDict,
pfod.py:13:or, sort of a data-only class. When an instance of the
pfod.py-14-class is created, all its fields are set to None if not
pfod.py-15-initialized.

Here we had two non-selected lines on either side, not in any color at all; and one selected line in the middle, with two occurrences of or within the one selected line.

In some cases the lines that would just be context, actually have a match:

pfod.py-47- self[field] = None
pfod.py-48- if len(kwargs):
pfod.py:49: raise TypeError('unexpected kwargs %s' % kwargs.keys())
pfod.py-50- if len(args):
pfod.py:51: raise TypeError('unconsumed args %r' % tuple(args))
pfod.py-52-
pfod.py-53- def __getattr__(self, attr):

Here we had two non-selected lines at the outer edges, then two selected lines with a non-selected line in between. This implies context lines can also be selected lines! They can have both non-matching text and matching text. There's something particularly weird about this, because if a context line has a match, it becomes a selected line—so why is there a matchContext at all? If a context line has a match, it changes into a selected line.

Normally, setting color.grep.matchContext never has any effect, because if there is a match within what would have been a context line, it changes into a selected line and color.grep.matchContext no longer applies. But when using -v everything gets swapped around. This is where the documentation defines (albeit not very well) the term selected:

-v, --invert-match

     Select non-matching lines.

That is, grep's -v option inverts the line selection. Normally, finding a match means the line is selected, so you get selected (default = none, but I set green above) and matchSelected (default = "bold red") colors. But with -v, every line that has a match is de-selected, and only non-matching lines are selected. So now what were context lines are selected, and matching lines are de-selected. So now for matching lines we get no color again, except for the match itself, where we get any matchContext color we set (default again "bold red"). (Of course, lines with the match only come out if you turn on context, since grep only outputs non-selected lines as context lines. You can also set color.grep.context to get those -v context-ized lines colorized.)

Finally:

match

     matching text (same as setting matchContext and matchSelected)

This is just shorthand to set both. When matchContext is useless (non--v), it effectively works out as an alias for matchSelected. When matchSelected is useless (-v), it effectively works out as an alias for matchContext. Git uses it internally to set the "bold red" default.