我能否让“git diff”只显示行号和更改的文件名?

335

这个问题需要“行号”。如果你不在意输出中的行号,请查看此问题和答案


基本上,我只想看到更改后的内容,而不是文件名和行号。


不是特别需要,但我需要它来书签标记我已经修改过的代码位置。 - wei
1
这的一个用途是将信息与代码覆盖率报告相结合,以评估提交中的新代码或修改代码是否被测试覆盖。 - AntonyG
@AntonyG 我在尝试构建一个与您完全相同的实用程序(覆盖率 vs 更改行)时发现了这个问题。您是否成功构建了报告?如果是,您是否在任何地方发布了它? - Andrew Newdigate
@AndrewNewdigate 这将是一个很酷的工具,但我从未构建过它。当我遇到这个问题时,我正在处理其他类型的代码覆盖率结果,但无法证明实现我的建议所需的时间是合理的。 - AntonyG
今天一个现代而简短的答案可能是git diff master --numstatgit diff master --compact-summary - undefined
显示剩余2条评论
12个回答

974
您可以使用此命令查看已更改的文件名,但无法显示行号:
git diff --name-only

开始进行差异比较吧!


111
这可能是大多数人在查看此页面时正在寻找的答案(对我来说是这样)。但是,它并没有回答原始问题,原始问题明确提到了行号。 - Pieter Müller
16
这不应该被接受作为答案,因为它只解决了问题的一半 - 你仍然需要输出哪些行(对于每个文件)已经被更改。 - adamwong246
1
为什么不使用“git status”?它也会告诉你未跟踪的文件。 - Naveen Paul
2
@JimmyPaul 因为有时候你已经提交了。例如,你需要列出主分支和你当前的高级分支之间已更改的文件 git diff --name-only master..HEAD - Hettomei
这很简单。为什么这个答案没有被标记为最佳呢? 这可能会让那些在最佳答案之后来查看却没有阅读其他答案的人感到困惑。 - Yury Bondarau
显示剩余4条评论

92

行号是指更改的行数还是包含更改的行号?如果您想获取更改的行数,请使用git diff --stat。这将给您一个类似于以下的显示:

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

无法获取更改本身的行号选项。


1
我在想实际的行号。不过还是谢谢。 - wei
我有点怀疑他想要一个GUI工具来完成这个任务。 - ThiefMaster

72
注意:如果您只是想查找更改文件的名称(没有标记已更改行的行号),请参见此处的另一个答案
对于这个问题Git本身没有内置选项(而且我认为它也不是很有用),但是可以通过使用"外部diff"脚本来实现。
下面是一个相当糟糕的脚本;需要您根据需要修复输出。
#! /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 '^[<>-]'

有关“外部差异”的详细信息,请参阅Git手册页GIT_EXTERNAL_DIFF的描述(大约在第700行左右,靠近末尾)。


1
谢谢。实际上我已经写了一个类似的脚本,在确认没有内置选项后,:) - wei
通过管道传输到 | grep -o '^[0-9]*' 可以只得到数字,假设您不关心右侧。 - GKFX
1
@DylanYoung 是的;为了限制显示的文件,添加 --diff-filter=...,其中 ... 部分是您想要查看的更改类型:M 表示修改,A 表示添加,D 表示删除,其他类型请参考 git diff 文档。 - torek
@Sventies:这不是OP要求的,正如我在我的答案顶部所指出的那样。他不仅仅想要文件的名称,他还想要带有行号的名称。 - torek
好的,@torek,没问题 :) - Sventies

52

使用:

git diff master --compact-summary

输出为:

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

这正是你所需要的。与你进行提交或从远程拉取新提交时相同的格式。

附注:很奇怪没有人以这种方式回答。


2
那个没有被指定。它是从一年前发布的2.18版本开始工作的。 - Seitbekir Seidametov
完美。这对我有用,响应很完美。 - Victor

24

1) 我最喜欢的:

git diff --name-status

在文件状态前添加内容,例如:

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

2) 如果您需要统计信息,则:

git diff --stat

将显示类似以下的内容:

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

3) 最后,如果您只想要文件名:

git diff --name-only

仅简单显示:

new_file.txt
modified_file.txt
deleted_file

5
显示每个文件的文件名和在当前版本与指定的提交版本之间更改的行数或数量:
git diff --stat <commit-hash>

2
在Windows上,这会过滤Git输出到文件和更改的行号: (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>

从中提取文件和更改的行需要做一些额外的工作: 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

1
最干净的输出,即仅文件名/路径,可通过以下方式获得:
git diff-tree --no-commit-id --name-only -r

0

这不是很好看,但这是一行 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

解释:

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

从Git中检索提交信息

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

在先前的答案基础上构建,并过滤掉只包含文件名和行号的行

  1. 将单行代码扩展为多行以提高可读性:
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

将字符串解析为期望输出:

file/name1.txt:34
file/name2.txt:98
file/name2.txt:101
file/name3.txt:2

0
git version 2.17.1 上,没有内置标志 来实现此目的。
以下是一个示例命令,用于从统一的差异中过滤出文件名和行号:
git diff --unified=0 | grep -Po '^diff --cc \K.*|^@@@( -[0-9]+,[0-9]+){2} \+\K[0-9]+(?=(,[0-9]+)? @@@)' | paste -s -d':'

例如,统一的差异:
$ 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

将导致:

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

为了匹配常见grep匹配结果的输出:
$ 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]+)? ):匹配diff --cc <filename>中的文件名,或者匹配@@@ <from-file-range> <from-file-range> <to-file-range>中的行号,或者匹配@@@后面的文本。
  2. sed -e '0~3{s/ @@@[ ]\?//}':从每个第三行开始删除@@@[ ]\?,以获取++<<<<<<< HEAD之前的可选1行上下文。
  3. sed '2~3 s/$/\n1/g':在第2行和第3行之间的每3行添加\n1,用于列号。
  4. sed "N;N;N;s/\n/:/g":将每3行连接成一个:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接