240

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.

1

7 Answers 7

316

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
6
  • 8
    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
    Commented Sep 15, 2013 at 9:12
  • 4
    I don't think git provides any way to avoid outputting those lines, because the diff would not make sense without them (you couldn't know which file you were looking at, nor where you were in the file). Commented Sep 15, 2013 at 9:19
  • 13
    @Rakesh: To expand, git-diff attempts to create diffs that can actually be used as patches to source files, which is impossible without that information. The only way to remove it would be to post-process it yourself, such as via git diff | egrep "^(\+|-) ". Commented Sep 15, 2013 at 9:23
  • 1
    git config --global diff.context 0 to have it set globally Commented Sep 2, 2015 at 16:40
  • If you want to see in a particular directory try git diff -U0 <dir> Commented Jul 26, 2017 at 14:19
73

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.
11
  • 2
    Nice one. Upvote for the clear explanation on each filter.
    – henrebotha
    Commented Oct 25, 2017 at 15:26
  • I see a lot of git diff "header" type lines which begin with @@, but what are git diff lines which begin with --- or +++? I wasn't aware of those ones. Commented May 21, 2020 at 6:43
  • Ah, nevermind. Those denote file names for files which contain additions (+++) or deletions (---). I see that here now: git-scm.com/docs/git-diff#_combined_diff_format. Commented May 21, 2020 at 6:45
  • Correction yet again: --- a/filename seems to denote the "file on the left", or the file as it was before, and +++ b/filename seems to denote the "file on the right", or the file as it is now with your changes. I'm so used to using git difftool with meld, which shows beautiful side-by-side comparisons, that I never really got used to looking at git diff, so it still looks strange to me, and I never really looked at these nuances before. Commented May 21, 2020 at 6:57
  • 1
    @GabrielStaples, support for color has been added. Thanks.
    – user650654
    Commented May 21, 2020 at 18:58
13

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

2
  • For cases where the line begins with "-" it won't work. Example: - name: No pdb in a yaml file. Commented Oct 26, 2018 at 7:57
  • FYI the [+|-] doesn't do what you think. It matches both + and - as well as | (which isn't what you want here). Change it to ^[+-][^+-]. Also, I think it should be either egrep or grep -E or grep -P
    – kelloti
    Commented Jun 8, 2022 at 1:28
7

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), 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 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 "^\+(?:(?!\+\+))|^-(?:(?!--))"'
2
  • 1
    this did not work for me on Windows git bash. Don't know why (grep said invalid option P), don't have the chutzpah to look into it at the moment.
    – Dennis
    Commented May 21, 2014 at 21:27
  • 1
    -P or --perl-regexp is used to interpret the pattern as a Perl regular rexpression, but is not always implemented. It didn't work for me on OSX. gnu.org/software/grep/manual/grep.html#grep-Programs Commented Sep 9, 2014 at 23:07
4

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.
1
3

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: Git diff to show only lines that have been modified
  3. Answer by @wisbucky: Git diff to show only lines that have been modified

Related:

  1. [my own answer] Git diff with line numbers (Git log with line numbers)
  2. [someone else's answer] Git diff with line numbers (Git log with line numbers)
  3. 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.
3

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: Git diff with line numbers (Git log with line numbers)
  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.

4
  • Since what version has diffc been available? Commented Oct 27, 2021 at 5:37
  • @SridharSarnobat, it's not part of git. I wrote git diffc in the awk programming language, as a simple wrapper around git diff. See my installation instructions at the top of my answer now. I just updated this answer. You should check out git diffn too, which I wrote as well. It's much more useful. Commented Oct 27, 2021 at 6:59
  • 1
    Ah I see, thanks for clarifying. Commented Oct 28, 2021 at 3:20
  • git diff -U0 FILE, git diff --unified=0 FILE both worked (Y)
    – Abhishek
    Commented Aug 2, 2023 at 12:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.