332

This question calls for "line numbers". If you do not care about line numbers in the output, see this question and answer.


Basically, I don't want to see the changed content, just the file names and line numbers.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
wei
  • 6,629
  • 7
  • 40
  • 52
  • I'm curious, are line numbers really useful without code? Or do you want the number of lines changed? – Andrew Marshall Mar 24 '12 at 01:27
  • well, not particularly, but I need it to bookmark where I have changed my code. – wei Mar 24 '12 at 01:32
  • 1
    One usage of this would be to combine the info with a code coverage report, to assess whether the new or modified code in a commit is covered by tests – AntonyG Nov 20 '15 at 10:20
  • @AntonyG I found this question while trying to build a utility that does exactly the same thing (coverage vs changed lines). Did you manage to build the report? If so, did you publish it anywhere? – Andrew Newdigate Feb 05 '16 at 10:09
  • @AndrewNewdigate it would be a cool tool but I never built it. I was doing some other kind of code coverage results processing when I came across this question, but couldn't justify the time required to implement my suggestion – AntonyG Feb 05 '16 at 14:11
  • So, you don't want to know what files have had their names changed? The question is ambiguous :/ – Max Waterman Jul 10 '20 at 05:51

12 Answers12

968

You can use this command to see the changed file names, but not with line numbers:

git diff --name-only

Go forth and diff!

mwfearnley
  • 3,303
  • 2
  • 34
  • 35
phreakhead
  • 14,721
  • 5
  • 39
  • 40
  • 111
    This is possible the answer most people are looking for when they view this page (it was for me). However, it doesn't answer the original question, which specifically mentions line numbers. – Pieter Müller Dec 02 '13 at 14:27
  • 16
    This should NOT be the accepted answer as it only solves half the problem- you still need to output which lines (for each file) that were changed. – adamwong246 Jan 24 '14 at 19:12
  • That's it! I was looking for this switch exactly! – Adam Arold Apr 12 '16 at 09:20
  • 1
    Why not use "git status"? It also tells you the untracked files. – Naveen Paul Nov 14 '16 at 13:45
  • 2
    @JimmyPaul because sometimes you already have commited. For example you need to list changed file between master and your current advanced branch `git diff --name-only master..HEAD` – Hettomei Jan 12 '17 at 15:50
  • So easy. Why this answer was not marked as best. It can confuse people who come and not read answers after the one marked as best. – Yury Bondarau Jun 15 '17 at 10:46
  • @PieterMüller I agree with you. But that's usually how it works. When you ask more than a question in one go, you usually don't get answer for all of them. – Daniel B Jun 06 '18 at 06:26
  • Does this require a particular version of `git`? It's not working for me, passing a hash to diff against (it just spits back the command usage instructions)... This alternative worked for me though: `git diff [hash] | grep diff` – poshaughnessy Jan 28 '19 at 15:48
  • @PieterMüller I do agree this is problematic as it's what I was looking for too. – Evan Carroll Jun 13 '20 at 21:27
92

Line numbers as in number of changed lines or the actual line numbers containing the changes? If you want the number of changed lines, use git diff --stat. This gives you a display like this:

[me@somehost:~/newsite:master]> git diff --stat
 whatever/views/gallery.py |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

There is no option to get the line numbers of the changes themselves.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
72

Note: if you're just looking for the names of changed files (without the line numbers for lines that were changed), see another answer here.


There's no built-in option for this (and I don't think it's all that useful either), but it is possible to do this in Git, with the help of an "external diff" script.

Here's a pretty crappy one; it will be up to you to fix up the output the way you would like it.

#! /bin/sh
#
# run this with:
#    GIT_EXTERNAL_DIFF=<name of script> git diff ...
#
case $# in
1) "unmerged file $@, can't show you line numbers"; exit 1;;
7) ;;
*) echo "I don't know what to do, help!"; exit 1;;
esac

path=$1
old_file=$2
old_hex=$3
old_mode=$4
new_file=$5
new_hex=$6
new_mode=$7

printf '%s: ' $path
diff $old_file $new_file | grep -v '^[<>-]'

For details on "external diff", see the description of GIT_EXTERNAL_DIFF on the Git manual page (around line 700, pretty close to the end).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
torek
  • 448,244
  • 59
  • 642
  • 775
  • 1
    Thanks. I actually have written a similar script, after having been confirmed that there is no built-in options for this, :) – wei Mar 25 '12 at 22:16
  • Piping to `| grep -o '^[0-9]*'` gives you just numbers, assuming you don't care about the right-hand side. – GKFX Dec 13 '16 at 17:33
  • 1
    @DylanYoung yes; to limit the files shown, add `--diff-filter=...` where the `...` part is the kind of changes you want to see: `M` for modified, `A` for added, `D` for deleted, and others per the `git diff` documentation. – torek May 17 '18 at 20:57
  • @Sventies: that's not what the OP asked for, as I note at the top of my answer. He does not want the *names* of the files alone. He wants the *names **with line numbers***. – torek Mar 14 '19 at 15:14
  • Fair enough @torek :) – Sventies Mar 15 '19 at 10:55
51

Use:

git diff master --compact-summary

The output is:

 src/app/components/common/sidebar/toolbar/toolbar.component.html   |  2 +-
 src/app/components/common/sidebar/toolbar/toolbar.component.scss   |  2 --

This is exactly what you need. The same format as when you are making a commit or pulling new commits from the remote.

PS: It's weird that nobody answered this way.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
24

1) My favorite:

git diff --name-status

Prepends file status, e.g.:

A   new_file.txt
M   modified_file.txt 
D   deleted_file.txt

2) If you want statistics, then:

git diff --stat

will show something like:

new_file.txt         |  50 +
modified_file.txt    | 100 +-
deleted_file         |  40 -

3) Finally, if you really want only the filenames:

git diff --name-only

Will simply show:

new_file.txt
modified_file.txt
deleted_file
Feiteira
  • 811
  • 8
  • 9
5

Shows the file names and amount/nubmer of lines that changed in each file between now and the specified commit:

git diff --stat <commit-hash>
masterxilo
  • 2,503
  • 1
  • 30
  • 35
2

On Windows, this filters the Git output to the files and changed line numbers:

(git diff -p --stat) | findstr "@@ --git"

diff --git a/dir1/dir2/file.cpp b/dir1/dir2/file.cpp
@@ -47,6 +47,7 @@ <some function name>
@@ -97,7 +98,7 @@ <another functon name>

To extract the files and the changed lines from that is a bit more work:

for /f "tokens=3,4* delims=-+ " %f in ('^(git diff -p --stat .^) ^| findstr ^"@@ --git^"') do @echo %f

a/dir1/dir2/file.cpp
47,7
98,7
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

The cleanest output, i.e. file names/paths only, comes with

git diff-tree --no-commit-id --name-only -r
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
RedFred
  • 999
  • 9
  • 20
0

On git version 2.17.1, there isn't a built-in flag to achieve this purpose.

Here's an example command to filter out the filename and line numbers from an unified diff:

git diff --unified=0 | grep -Po '^diff --cc \K.*|^@@@( -[0-9]+,[0-9]+){2} \+\K[0-9]+(?=(,[0-9]+)? @@@)' | paste -s -d':'

For example, the unified diff:

$ git diff --unified=0
diff --cc foobar
index b436f31,df63c58..0000000
--- a/foobar
+++ b/foobar
@@@ -1,2 -1,2 +1,6 @@@ Line abov
++<<<<<<< HEAD
 +bar
++=======
+ foo
++>>>>>>> Commit message

Will result in:

❯ git diff --unified=0 | grep -Po '^diff --cc \K.*|^@@@( -[0-9]+,[0-9]+){2} \+\K[0-9]+(?=(,[0-9]+)? @@@)' | paste -s -d':'
foobar:1

To match the output of commands in common grep match results:

$ git diff --unified=0 | grep -Po '^diff --cc \K.*|^@@@( -[0-9]+,[0-9]+){2} \+\K[0-9]+(?=(,[0-9]+)? )| @@@.*' | sed -e '0~3{s/ @@@[ ]\?//}' | sed '2~3 s/$/\n1/g' | sed "N;N;N;s/\n/:/g"
foobar:1:1:Line abov
  1. grep -Po '^diff --cc \K.*|^@@@( -[0-9]+,[0-9]+){2} \+\K[0-9]+(?=(,[0-9]+)? ): Match filename from diff --cc <filename> OR Match line number from @@@ <from-file-range> <from-file-range> <to-file-range> OR Match remaining text after @@@.
  2. sed -e '0~3{s/ @@@[ ]\?//}': Remove @@@[ ]\? from every 3rd line to get the optional 1 line context before ++<<<<<<< HEAD.
  3. sed '2~3 s/$/\n1/g': Add \n1 every 3 lines between the 2nd and 3rd line for the column number.
  4. sed "N;N;N;s/\n/:/g": Join every 3 lines with a :.
Edgar Lee
  • 1
  • 1
0

I use grep as a naive solution.

$ git diff | grep -A2 -- '---'

An output example:

--- a/fileA.txt
+++ b/fileA.txt
@@ -0,0 +1,132 @@
--
--- a/B/fileC.txt
+++ b/B/fileC.txt
@@ -33663,3 +33663,68800 @@ word_38077.png,Latin
--
--- a/D/fileE.txt
+++ b/D/fileE.txt
@@ -17998,3 +17998,84465 @@ word_23979.png,Latin
--
--- a/F
+++ b/F
@@ -1 +1 @@

Maybe you can see the colored output. It helps you to read the output easily.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
plhn
  • 5,017
  • 4
  • 47
  • 47
0

Try to use:

git dif | grep -B <number of before lines to show> <regex>

In my case, I tried to search for where I had put a debug statement in the many files. I needed to see which file already got this debug statement like this:

git diff | grep -B 5 dd\(
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user5518501
  • 1
  • 1
  • 1
0

It's not pretty but here's one line of bash:

git diff --unified=0 HEAD~1..HEAD | grep -Po '(^diff --git [a-zA-Z/._]*|^@@.*@@)' | while read l; do if [[ -n ${l##@@*} ]]; then f=${l#*/}; else echo "$f:${l##@@ }" | cut -d' ' -f1 | tr -d '-'; fi; done

Explanation:

  1. git diff --unified=0 HEAD~1..HEAD

Retrieves the commit info from Git

  1. grep -Po '(^diff --git [a-zA-Z/._]*|^@@.*@@)'

Builds on a prior answer and filters down to lines containing filenames and line numbers

  1. Expanding the one-liner into multiple lines for readability's sake:
while read line; do
  if [[ -n ${line##@@*} ]]; then
    # Grabs filename from this pattern: "diff --git a/....."
    filename=${line#*/};
  else
    # Grabs line number from this patterns: "@@ -<line> +<line> @@"
    echo"$filename:${line##@@ }" | cut -d' ' -f1 | tr -d '-';
  fi;
done

String parsing that converts into expected output:

file/name1.txt:34
file/name2.txt:98
file/name2.txt:101
file/name3.txt:2
Matt Kneiser
  • 1,982
  • 18
  • 23