Git diff to show only lines that have been modified

GitDiff

Git Problem Overview


When I do a git diff, it shows lines that have been added:

+ this line is added

lines that have been removed:

- this line is removed

but it also shows many lines which are not modified:

this line is not modified
this line is also not modified

This results in the actual git diff looking something like this:

+ this line is added
  this line is not modified
- this line is removed
  this line is not modified

Can I ask git to show only lines that have been modified and ignore all other code which has not been modified? I have written a method which will remove all the lines which don't have a "+" or "-" sign in front of them, but I am sure there must be a simpler way to do this.

In my git diff, I am only interested in seeing the lines that have been modified.

Git Solutions


Solution 1 - Git

What you want is a diff with 0 lines of context. You can generate this with:

git diff --unified=0

or

git diff -U0

You can also set this as a config option for that repository:

git config diff.context 0

To have it set globally, for any repository:

 git config --global diff.context 0

Solution 2 - Git

Another hack (on un*x) to show just the lines beginning with + and -:

git diff -U0 | grep '^[+-]' | grep -Ev '^(--- a/|\+\+\+ b/)'

The code above does the following:

  • git diff -U0: choose 0 context lines
  • The first grep only includes all lines starting with + or -
  • The second grep excludes lines starting with --- a/ or +++ b/

Color

To show colored diff, try the following:

git diff -U0 --color | grep '^\e\[[^m]*m[-+]' | grep -Ev '(--- a/|\+\+\+ b/)'
  • The expression, ^\e\[[^m]*m[-+], looks for start of line (^), then the escape characer (\e) followed by [ which together start the escape sequence, then any character that is not an "m" (numbers, semicolons, or nothing), followed by an "m" which ends the escape sequence.
  • Note that all of the following are valid escape sequences: \e[0m (reset), \e[m (also reset), \e[1m (bold on), \e[31m (red), \e[32m (green), \e[9;31m (strike out + red), \e[31;9m (red + strike out), \e[1;4;9;31m (bold + underline + strike out + red). The default git colors use red and green, but they can be reconfigured.
  • --color is the same as --color=always.
  • The restriction on --- a/ or +++ b/ to appear at the start of the line has been removed to accommodate for the escape sequences and this could lead to an edge case.

Additional Notes:

  • The above solution needs to be modified if you use additional git diff options such as -R, --src-prefix, --dst-prefix, --no-prefix, etc.
  • The two greps can be combined into a single grep -E -v '^(\+\+\+ b/|--- a/|@@ |diff --git|index )', but I find the double grep version easier to understand.

Solution 3 - Git

I think for simple cases the regex can be much shorter and easier to remember, with the caveat that this won't work if you have line changes where the line itself starts with + or -

$ git diff | grep '^[+|-][^+|-]'

The regex says the line should start with + or -, and the immediately following character should be neither of those. I got the same results whether I escaped the + or not here, btw...


Example:

$ cat testfile
A
B
C
D
E
F
G

Say I change C to X, E to Y, and G to Z.

$ git diff | grep '^[+|-][^+|-]'
-C
+X
-E
+Y
-G
+Z

Like I said above, though, this is just for most cases. If you pipe that output to a file dout, then try the same regex, it won't work.

$ git diff dout | grep '^[+|-][^+|-]'
$

Anyways, hope that helps in your case

Solution 4 - Git

Following up on Chris' latest comment, the main problem with the post-processing is that you want to keep lines starting with -|+ but you also want to filter out those that start with ---|+++. If you are storing patch files in your repo (I do, in [Pydoop][1]), on the other hand, you want to keep lines that start with --|++, so the regexp becomes a bit involved:

git diff | grep -P '^\+(?:(?!\+\+))|^-(?:(?!--))'

The regexp uses a negative lookahead: see Peter Boughton's answer to [this question][2] for a detailed explanation.

If you do this often, you might want to set up a git alias for it:

git config --global alias.diffonly '!git diff | grep -P "^\+(?:(?!\+\+))|^-(?:(?!--))"'

[1]: https://github.com/crs4/pydoop "Pydoop git repository" [2]: https://stackoverflow.com/questions/977251/regular-expressions-and-negating-a-whole-character-group

Solution 5 - Git

This answer will retain the original red/green colors for readability. I provided a few variations in syntax:

git diff --color | grep --color=never $'^\e\[3[12]m'
git diff --color | grep --color=never $'^\033\[3[12]m'
git diff --color | grep --color=never -P '^\e\[3[12]m'
git diff --color | grep --color=never -P '^\033\[3[12]m'

Explanation:

  • The git diff --color is needed to prevent git from disabling the color when it is piping.
  • The grep --color=never is to prevent grep removing the original color and highlighting the matched string.
  • We are matching for lines that start with red (\e[31m) or green (\e[32m) escape codes.
  • The $'...' (ANSI-C quoting syntax) or -P (perl syntax) is to let grep to interpret \e or \033 as an ESC character.

Solution 6 - Git

> Can I ask git to show only lines that have been modified and ignore all other code which has not been modified?

And from the OP's follow-up comment under the main answer:

> Thank you for quick reply. This solves half of my problem but I am still getting some lines like @@ -1 +1 @@ in my diff and top of my git diff have diff --git a/db/xxxxxxx b/db/xxxx index xxxxx..aaaaaaa bbbbbbbb. -r3b00t

To solve both of those requests above, here is the 1-line solution using the git-diffc.sh awk-language-based wrapper I wrote around git diff:

git diffc

Done!

Here are the features of git diffc.
All these features, when taken together, solve the shortcomings of every other answer here:

  1. It handles color AND no-color output. That's what this regular expression does: ^(\033\[(([0-9]{1,2};?){1,10})m)?
  2. It handles ALL COLORS and ALL TEXT FORMATTING OPTIONS, including bold, italics, strikethrough, etc, which you can set in your git config settings. That's why the regex above has ;? and {1,10} in it: if it detects the start of a color or text formatting code, it will match up to 10 sequences of these combined ANSI codes.
  3. It does NOT also include lines which begin with @@ and the word diff, as the accepted answer does. If you DO want those lines (which quite frankly, I think are useful :) ), do this instead:
    git diff --unified=0
    
    or
    git diff -U0
    
  4. It shows the output in the same exact way as git diff would: in the less pager with optional color output (-R), and only if the text is > 1 page (-F), and while retaining the current page of text on the screen when you quit (-X).

It also has the benefit of being powerful and easily configurable since it uses the awk programming language.

Sample output of git diff 8d4d4fd3b60f200cbbb87f2b352fb097792180b2~2..8d4d4fd3b60f200cbbb87f2b352fb097792180b2~3:

> diff --git a/useful_scripts/rg_replace.sh b/useful_scripts/rg_replace.sh > index 74bc5bb..0add69d 100755 > --- a/useful_scripts/rg_replace.sh > +++ b/useful_scripts/rg_replace.sh > @@ -2,12 +2,11 @@ >
> # This file is part of eRCaGuy_dotfiles: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles >
> -# STATUS: functional and ready-to-use > - > +# WORK IN PROGRESS! <=========== > # This is a simple wrapper around RipGrep (rg) to allow in-place find-and-replace, since the > # rg --replace option replaces only the stdout, NOT the contents of the file. > # man rg under the --replace section states: "Neither this flag nor any other ripgrep > -# flag will modify your files." This wrapper overcomes that limitation. > +# flag will modify your files." >
> # INSTALLATION INSTRUCTIONS: > # 1. Install RipGrep: https://github.com/BurntSushi/ripgrep#installation

versus the sample output of git diffc 8d4d4fd3b60f200cbbb87f2b352fb097792180b2~2..8d4d4fd3b60f200cbbb87f2b352fb097792180b2~3. Notice that only - and + lines are shown, whereas surrounding context lines are gone, and all other lines such as diff, index, ---, +++, and @@ are gone too!:

> -# STATUS: functional and ready-to-use > - > +# WORK IN PROGRESS! <=========== > -# flag will modify your files." This wrapper overcomes that limitation. > +# flag will modify your files."


git diffc stands for "git diff changes", meaning: show just the changed lines of code, nothing else. I wrote it. It is not part of regular git.

It supports ALL options and parameters supported by git diff, since it's just a light-weight wrapper around git diff.

Download it here: git-diffc.sh. It is part of my eRCaGuy_dotfiles repo.

To install it:

git clone https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles.git
cd eRCaGuy_dotfiles/useful_scripts
mkdir -p ~/bin
ln -si "${PWD}/git-diffc.sh" ~/bin/git-diffc

Now manually log out and log back in now if this is the first time you've ever created or used the ~/bin dir, in order to cause Ubuntu's default ~/.profile file to add ~/bin to your PATH variable. If logging out and back in doesn't work, add the following few lines of code to your ~/.profile file and then log out of Ubuntu and log back in again:

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

That's it!

Usage: same as git diff. Ex:

git diffc
git diffc -h
git diffc commit1 commit2
git diffc --no-color
# etc.

Additional installation notes:

See also the installation section of my other answer about git diffn, which I also wrote, here. Except, everywhere you see git-diffn in those instructions, use git-diffc instead. That includes inside the wget command too. Downloading and installing git diffc is easy: it's just a few commands.

How to use awk to show just the + and - lines, accounting for any color or text formatting git diff may be outputting:

This code below is what makes up the git diffc wrapper.

Not a single one of the other answers here (including my other answer) will do exactly what you want 100% correctly. This answer, however, will. Here is a 1-liner you can copy and paste into your terminal. I've just made it multiple lines for readability--you can copy-paste it the same either way so I might as well make it readable! It relies on the awk programming language:

git diff --color=always "$@" | awk '
# 1. Match and then skip "--- a/" and "+++ b/" lines
/^(\033\[(([0-9]{1,2};?){1,10})m)?(--- a\/|\+\+\+ b\/)/ {
    next 
} 
# 2. Now print the remaining "+" and "-" lines ONLY! Note: doing step 1 above first was required or
# else those lines would have been matched by this matcher below too since they also begin with 
# the "+" and "-" symbols.
/^(\033\[(([0-9]{1,2};?){1,10})m)?[-+]/ {
    print $0 
}
' | less -RFX

If you are interested in learning awk, here are some resources:

  1. gawk (GNU awk) manual: https://www.gnu.org/software/gawk/manual/html_node/index.html#SEC_Contents
  2. Study git diffn and the comments therein: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/useful_scripts/git-diffn.sh
  3. If you want git diffn too, which is git diff with line numbers, see here: https://stackoverflow.com/questions/24455377/git-diff-with-line-numbers-git-log-with-line-numbers/61997003#61997003
  4. Some awk "hello world" and syntax test examples: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/awk

As a bonus, I also wrapped up the above to be used as git diffc, which means "git diff to show ONLY 'c'hanges". Usage is identical to git diff; just use git diffc instead! It supports ALL options. Color is ON by default. To turn it off, simply use git diffc --no-color or git diffc --color=never. See man git diff for details.

Since I just finished git diffn (a tool to show git diff with line 'n'umbers) last night, writing git diffc was trivial. I figured I better do it now while the knowledge is fresh in my head.

Solution 7 - Git

Here's another, simpler way to find only lines which have been modified, and hence begin with a single + or -, while retaining color output:

git diff -U0 --color=always HEAD~ | grep --color=never -E $'^\e\[(32m\+|31m-)'
  1. The -U0 says to include 0 lines of context around the changed lines--ie: include just the changed lines themselves. See man git diff.
  2. The -E for grep allows it to work with extended regular expressions
  3. The $'' syntax apparently allows ANSI quoting, which properly interprets the ESC (escape, or 0x1b) character properly. See here.
  4. And here's the regex description from https://www.regex101.com: enter image description here
  5. Basically, ^ matches the beginning of the line, \e matches the Escape char, which is the start of a color code in the terminal, \[ matches the next char in the color code, which is [, and then the (this|that) syntax matches "this" or "that", where "this" is 32m+, which is a green + line, and 31m- is a red - line.
  6. Colors are like this: \e[32m is green and \e[31m is red.
  7. + shows lines marked by git diff as added, of course, and - shows lines marked by git diff as deleted.
  8. Note that --color=never is required in the 2nd grep expression in order to prevent it from highlighting its matches, which would otherwise screw up the color codes coming in from git diff to the left.
  9. The + has to be escaped too as \+ because otherwise the + is a special regular expression (regex) character which specifies one or more occurrences of the preceding element. See here: https://en.wikipedia.org/wiki/Regular_expression#Basic_concepts.

References:

  1. https://git-scm.com/docs/git-diff#_combined_diff_format
  2. Answer by @user650654: https://stackoverflow.com/questions/18810623/git-diff-to-show-only-lines-that-have-been-modified/26622262#26622262
  3. Answer by @wisbucky: https://stackoverflow.com/questions/18810623/git-diff-to-show-only-lines-that-have-been-modified/57579094#57579094
  1. [my own answer] https://stackoverflow.com/questions/24455377/git-diff-with-line-numbers-git-log-with-line-numbers/61997003#61997003
  2. [someone else's answer] https://stackoverflow.com/questions/24455377/git-diff-with-line-numbers-git-log-with-line-numbers/33249416#33249416
  3. https://stackoverflow.com/questions/61932427/git-diff-with-line-numbers-and-proper-code-alignment-indentation
  4. git-filechange-search.sh - a script which allows you to search a file for a variable or function name and figure out which commits contain changes with that variable or function name. Ex. usage: ./git-filechange-search.sh path/to/my/file.cpp variable_name will find all commits with changes to file.cpp that contain variable_name in them. This is useful to see where and when certain features were changed. It's as though it were a search that could observe sections of a file displayed via git blame over time.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionr3b00tView Question on Stackoverflow
Solution 1 - GitChris HayesView Answer on Stackoverflow
Solution 2 - Gituser650654View Answer on Stackoverflow
Solution 3 - GitgaloisView Answer on Stackoverflow
Solution 4 - GitsimleoView Answer on Stackoverflow
Solution 5 - GitwisbuckyView Answer on Stackoverflow
Solution 6 - GitGabriel StaplesView Answer on Stackoverflow
Solution 7 - GitGabriel StaplesView Answer on Stackoverflow