192

git diff --stat and git log --stat show output like:

$ git diff -C --stat HEAD c9af3e6136e8aec1f79368c2a6164e56bf7a7e07
app/controllers/application_controller.rb |   34 +++-------------------------
1 files changed, 4 insertions(+), 30 deletions(-)

But what really happened in that commit was that 4 lines were changed and 26 lines were deleted which is different than adding 4 lines and deleting 30.

Is there any way of getting the delta LOCs (26 in this case)? I don't really care about differentiating between lines added or removed.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Juan Alonso
  • 2,125
  • 2
  • 15
  • 16

5 Answers5

203

You can use:

git diff --numstat

to get numerical diff information.

As far as separating modification from an add and remove pair, --word-diff might help. You could try something like this:

MOD_PATTERN='^.+(\[-|\{\+).*$' \
ADD_PATTERN='^\{\+.*\+\}$' \
REM_PATTERN='^\[-.*-\]$' \
git diff --word-diff --unified=0 | sed -nr \
    -e "s/$MOD_PATTERN/modified/p" \
    -e "s/$ADD_PATTERN/added/p" \
    -e "s/$REM_PATTERN/removed/p" \
    | sort | uniq -c

It's a little long-winded so you may want to parse it in your own script instead.

Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
quornian
  • 9,495
  • 6
  • 30
  • 27
  • 3
    Thanks quornian but numstat gives exactly the same info as stat, additions and deletions. – Juan Alonso Mar 30 '12 at 14:19
  • Updated my answer to include an example use of `--word-diff`. That might be more useful. – quornian Apr 01 '12 at 19:53
  • Thanks! Your edited answer is great. I wanted to see how many lines were added/modified/removed between two specific commits. To others who may wish to do the same, just put the branch names in the command, as in: `git diff commit1 commit2 --word-diff ...` where commit1/2 are SHA1s, branches, tags, etc... – Drew Noakes Nov 24 '13 at 19:04
  • 25
    The output of `git diff --numstat` is broken down by file. To see the total added/removed for the diff, you can pipe it to awk: `git diff --numstat | awk '{ added += $1; removed += $2 } END { print "+" added " -" removed }'` – hughes Dec 01 '15 at 02:49
  • 56
    @hughes A simpler way of obtaining the same information would be `git diff --shortstat`. In my experience it is equivalent to accumulating the output of `git diff --numstat`. – klaus triendl Sep 09 '18 at 12:30
  • 4
    Also FWIW to see the stats for staged changes, simply add `--cached` – xlm Nov 07 '18 at 06:56
  • In case anyone else is wondering about the output from `--numstat`, the two numbers are lines added and lines removed in that order, so `1 10 test/some_test.rb` means 1 added and 10 removed. – Sam Mar 08 '22 at 12:04
115
  1. If you want to know the lines added/changed/deleted by a commit with id commit-id, you could use

    git show commit-id --stat
    

    or

    git diff commit-id-before commit-id --stat
    
  2. If you wat to know the lines added/changed/deleted by a range commits, you could use

    git diff commit-id1 commit-id2 --stat
    
  3. If you want to know the lines added/changed/deleted by each commit, you could use

    git log --stat
    
wjandrea
  • 28,235
  • 9
  • 60
  • 81
yhluo
  • 1,307
  • 1
  • 8
  • 5
  • 2
    That solution doesn't answer the question, "git --stat" counts a single modified line as "1 insertion and 1 deletion". The question asks how to get "1 changed". – Juan Alonso May 01 '20 at 10:31
29

You could use diffstat to show the number of modified lines. For example:

git diff HEAD c9af3e6136e8 | diffstat -Cm

The -C option is for getting colorized output; the -m option is for showing the number of modified lines. Sample output:

 app/controllers/application_controller.rb |   30 -------------------!!!
 1 files changed, 0 insertions(+), 26 deletions(-), 4 modifications(!)

Note that the number of lines in each category (insertions, deletions, modifications) is only approximate, as man diffstat says:

-m merge insert/delete counts from each "chunk" of the patch file to approximate a count of the modified lines.

diffstat has a missing feature when compared to git diff --stat: diffstat is incapable of showing file moves/renames (e.g. app/{a.rb => b.rb}), unlike git diff --stat which is capable of showing this information by using the -M (--find-renames) option or by setting diff.renames in the git configuration file (refer to man git-config).

Flux
  • 9,805
  • 5
  • 46
  • 92
16

If all of your files are staged for commit, to see the --numstat go like this:

git diff --numstat --cached

example output

32      32      project.pbxproj

--numstat [...] shows number of added and deleted lines

Gianfranco P.
  • 10,049
  • 6
  • 51
  • 68
Falieson
  • 2,198
  • 3
  • 24
  • 35
5

git uses "unified" diff, which only has added and deleted lines, as the diff format. You have to do something external to get a diff that shows add, delete, and change information.

https://wiki.postgresql.org/wiki/Working_with_Git#Context_diffs_with_Git gives links to a script that allows running regular old "diff" - and from that you can generate a "context" diff output. Context diff does show added, removed, and changed lines, which should allow you to get the data you want.

Daniel Pittman
  • 16,733
  • 4
  • 41
  • 34
  • 2
    Voted down for linking to an article instead of reproducing the relevant information here. The article no longer contains the relevant section. (Admittedly, it happens to be a wiki with available edit history, but Stack Overflow answers should stand on their own regardless.) – Amir Dec 28 '21 at 14:04
  • For anyone who wants to easily get to the content that was removed in an edit, here a link to the old page: https://wiki.postgresql.org/index.php?title=Working_with_Git&oldid=31690#Context_diffs_with_Git – Michael Burr Jan 14 '22 at 22:23