Git diff只显示修改过的行

226

当我执行 git diff 命令时,它会显示已添加的行:

+ this line is added

已删除的行:

- this line is removed

但它还显示了许多未修改的行:

this line is not modified
this line is also not modified

这导致实际的git diff看起来像这样:
+ this line is added
  this line is not modified
- this line is removed
  this line is not modified

我可以请教git只显示已修改的行并忽略所有未修改的代码吗?我编写了一种方法,可以删除没有“+”或“-”符号的所有行,但我确定肯定有更简单的方法来实现这一点。
在我的git diff中,我只关心看到已修改的行。

尝试使用我的git diffc - Gabriel Staples
7个回答

295

你想要的是一个没有上下文行的 diff。你可以使用以下命令生成:

git diff --unified=0
或者
git diff -U0

您还可以将此设置为该代码库的配置选项:

git config diff.context 0

要在全局范围内设置它,适用于任何存储库:

 git config --global diff.context 0

8
感谢您的快速回复。这解决了我问题的一半,但是我仍然在我的差异中看到一些行,例如“@@ -1 +1 @@”,并且我的git diff顶部有“diff--git a/db/xxxxxxx b/db/xxxx index xxxxx..aaaaaaa bbbbbbbb”。 - r3b00t
4
我认为 Git 没有提供任何避免输出这些行的方法,因为如果没有它们,diff 不会有意义(你无法知道你正在查看哪个文件,以及你在文件中的位置)。 - Chris Hayes
13
为了扩展一下,git-diff试图创建实际可用作源文件补丁的差异,若没有这些信息则不可能。唯一能删除它的方法是自行进行后处理,例如通过git diff | egrep "^(\+|-) " - Chris Hayes
1
git config --global diff.context 0 要全局设置。 - Andrzej Rehmann
如果您想查看特定目录中的内容,请尝试使用以下命令:git diff -U0 - Eswar Yaganti
我刚刚完成了编写 git diffn,它是一个 git diff 的包装器,显示行号。我处理那些 @@ 行来弄清楚它们。一旦我完成了这个,编写 git diffc 仅显示 'c' 改变的行,就像 @r3b00t 想要的那样,非常简单,所以我编写并在这里发布了它:https://dev59.com/0GMk5IYBdhLWcg3w-Ceq#62009746。一旦你理解了 awk 编程语言的基础知识,它就很容易配置。与这里的所有其他答案不同,它处理您的 git diff 输出可能包含的所有颜色代码和文本属性格式,包括粗体、斜体、删除线等。 - Gabriel Staples

67

在Unix系统中,另一个仅显示以+-开头的行的技巧:

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

上面的代码执行以下操作:

  • git diff -U0:选择0个上下文行。
  • 第一个 grep 只包括以 +- 开头的所有行。
  • 第二个 grep 排除以 --- a/+++ b/ 开头的行。

颜色

要显示彩色差异,请尝试以下操作:

git diff -U0 --color | grep '^\e\[[^m]*m[-+]' | grep -Ev '(--- a/|\+\+\+ b/)'
  • 表达式^\e\[[^m]*m[-+]查找行的开头(^),然后是转义字符(\e),接下来是左中括号([),它们一起开始转义序列,然后是任何不是"m"的字符(数字、分号或空),最后是结束转义序列的"m"。
  • 请注意以下所有转义序列都是有效的:\e[0m(重置),\e[m(也是重置),\e[1m(加粗),\e[31m(红色),\e[32m(绿色),\e[9;31m(删除线+红色),\e[31;9m(红色+删除线),\e[1;4;9;31m(加粗+下划线+删除线+红色)。默认的git颜色使用红色和绿色,但可以重新配置。
  • --color--color=always相同。
  • 由于转义序列,对于以--- a/+++ b/开头的行已经取消了限制,这可能会导致一个边缘情况。
  • 如果使用其他git diff选项(如-R--src-prefix--dst-prefix--no-prefix等),则需要修改上述解决方案。
  • 两个grep可以合并为单个grep -E -v '^(\+\+\+ b/|--- a/|@@ |diff --git|index )',但我认为双grep版本更容易理解。

2
很好。对于每个过滤器的清晰解释点赞。 - henrebotha
我看到很多以 @@ 开头的 git diff "header" 类型行,但是以 ---+++ 开头的 git diff 行是什么?我不知道那些是干什么的。 - Gabriel Staples
啊,没事了。那些表示文件名的符号是用来表示包含添加(+++)或删除(---)的文件的。我现在在这里看到了:https://git-scm.com/docs/git-diff#_combined_diff_format。 - Gabriel Staples
我想看到颜色,所以我使用 git diff -U0 --color=always ...,但这会弄乱它,因为现在显然颜色代码首先出现,而不是 +-。我们该如何克服这个问题? - Gabriel Staples
1
@GabrielStaples,已添加颜色支持。谢谢。 - user650654
显示剩余4条评论

13

我认为对于简单的情况,正则表达式可以更短、更容易记忆,但需要注意:如果在行首出现 +-,那么这种简写方式将不再适用。

$ git diff | grep '^[+-][^+-]'
正则表达式表示该行应以+-开头,并且紧随其后的字符不应为这两个字符之一。顺便说一句,无论我是否在此处转义+,我得到的结果都是相同的...
示例:
$ cat testfile
A
B
C
D
E
F
G

假设我将C改为XE改为YG改为Z

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

就像我之前所说的那样,这仅适用于大多数情况。如果您将该输出导入文件dout,然后尝试相同的正则表达式,它将无法工作。

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

无论如何,希望这对您有所帮助


对于以“-”开头的行,它将无法正常工作。例如:在yaml文件中的“- name: No pdb”。 - anapaulagomes
FYI,[+|-] 不像你想的那样工作。它匹配 +- 以及 | (这不是你想要的)。将其更改为 ^[+-][^+-]。此外,我认为应该使用 egrepgrep -Egrep -P - kelloti

7

针对Chris的最新评论,后处理的主要问题在于您想保留以-|+开头的行,但是您也想过滤掉以---|+++开头的行。另一方面,如果您在仓库中存储补丁文件(我在Pydoop中这样做),则希望保留以--|++开头的行,因此正则表达式变得有点复杂:

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

这个正则表达式使用了负向先行断言:详细的解释请查看Peter Boughton对该问题的回答

如果您经常使用这种方法,可以为此设置一个git别名:

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

1
这在 Windows 的 Git Bash 上对我不起作用。不知道为什么(grep 说选项 P 无效),目前没有勇气去研究它。 - Dennis
1
-P--perl-regexp 用于将模式解释为 Perl 正则表达式,但并非总是被实现。在我的 OSX 上无法工作。http://www.gnu.org/software/grep/manual/grep.html#grep-Programs - Willington Vega

4

为了易读性,本答案会保留原有的红色/绿色颜色。我提供了几种语法变体:

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'

解释:

  • 需要使用命令git diff --color以防止在脱管时禁用颜色。
  • 使用命令grep --color=never可防止grep删除原始颜色并突出显示匹配的字符串。
  • 我们要匹配以红色(\e[31m)或绿色(\e[32m)转义代码开头的行。
  • $'...'(ANSI-C引用语法)或-P(perl语法)使得grep将解释\e\033作为一个ESC字符。

谢谢这个。这是我刚想到的另一种形式。你的 $'' 部分特别有帮助。https://dev59.com/0GMk5IYBdhLWcg3w-Ceq#61929887 - Gabriel Staples

3
我能否要求git仅显示已修改的行并忽略所有未修改的代码?
并且从主答案下OP的跟进评论
谢谢您的快速回复。这解决了我的一半问题,但我仍然会得到一些像@@-1+1@@这样的行在我的diff中,并且我的git diff顶部有diff--git a/db/xxxxxxx b/db/xxxx索引xxxxx..aaaaaaa bbbbbbbb。-r3b00t
为了解决上述两个请求,这是使用我编写的基于awk语言的git-diffc.sh包装器的1行解决方案:
git diffc

完成!

这里是git diffc的特点。
所有这些特点,综合起来,解决了其他答案中存在的缺陷:

  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).

它还有一个优点,就是使用awk编程语言,因此功能强大且易于配置。

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

git diffc 8d4d4fd3b60f200cbbb87f2b352fb097792180b2~2..8d4d4fd3b60f200cbbb87f2b352fb097792180b2~3的样本输出相比较。注意,只有-+行被显示出来,周围的上下文行消失了,而所有其他的行,如diffindex---+++@@也都消失了!:

-# 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代表“git diff changes”,意思是:仅显示已更改的代码行,不显示其他内容。我编写了它。 它不是常规git的一部分。

它支持git diff支持的所有选项和参数,因为它只是git diff的轻量级包装器。

在此处下载: git-diffc.sh. 它是我的eRCaGuy_dotfiles repo的一部分。

要安装它:

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

如果这是您第一次创建或使用~/bin目录,请手动注销并重新登录,以使Ubuntu默认的~/.profile文件将~/bin添加到您的PATH变量中。如果注销并重新登录无效,请将以下几行代码添加到您的~/.profile文件中,然后再次注销Ubuntu并重新登录:

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

就是这样!

用法:git diff 相同。例如:

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

安装补充说明:

另请参阅我关于 git diffn 的安装部分的其他答案,该答案也是我编写的,在这里。除此之外,你需要在那些说明中的任何地方使用 git-diffc 替换 git-diffn。这也包括 wget 命令内部。下载和安装 git diffc 很容易:只需执行几个命令即可。

如何使用 awk 仅显示 +- 行,考虑到 git diff 可能输出的任何颜色或文本格式:

下面的代码是构成 git diffc 包装器的内容。

这里的其他答案(包括我的另一个答案)都不能完全满足您的要求。然而,这个答案可以。以下是一个可以复制粘贴到终端的一行代码,我将其分成多行以提高可读性--无论哪种方式您都可以复制粘贴它,所以我不妨让它更易读! 它依赖于awk编程语言:

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

如果你有兴趣学习awk,这里有一些相关资源:
  1. gawk(GNU awk)手册:https://www.gnu.org/software/gawk/manual/html_node/index.html#SEC_Contents
  2. 学习git diffn以及其中的注释:https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/useful_scripts/git-diffn.sh
  3. 如果您也想要git diffn,它是带有行号的git diff,请参见此处:带有行号的Git diff(带有行号的Git日志)
  4. 一些awk“hello world”和语法测试示例:https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/awk
作为奖励,我还将上述内容包装成git diffc供使用,意思是“仅显示‘更改’的git diff”。用法与git diff完全相同;只需使用git diffc即可!它支持所有选项。默认情况下为彩色。要关闭它,只需使用git diffc --no-colorgit diffc --color=never。有关详细信息,请参见man git diff
由于昨晚刚完成了git diffn(一个显示带有行号的git diff的工具),编写git diffc非常简单。我想在知识还新鲜的时候就把它做好。

diffc 从哪个版本开始提供? - Sridhar Sarnobat
@SridharSarnobat,这不是git的一部分。我用awk编程语言编写了git diffc,作为git diff的简单包装器。现在请查看我的安装说明。我刚刚更新了这个答案。你也应该看看我写的git diffn,它更加有用。 - Gabriel Staples
1
啊,我明白了,谢谢你的澄清。 - Sridhar Sarnobat
git diff -U0 FILE, git diff --unified=0 FILE 都可以使用(Y) - Abhishek

2
这里有另一种更简单的方法,可以找到仅被修改过的行,因此以单个+-开头,同时保留彩色输出:
git diff -U0 --color=always HEAD~ | grep --color=never -E $'^\e\[(32m\+|31m-)'

  1. -U0表示在更改的行周围包括0行上下文,也就是仅包括更改的行本身。详见man git diff
  2. -E用于grep,允许其使用扩展正则表达式。
  3. $''语法显然允许ANSI引用,可以正确解释转义字符ESC(转义,或0x1b)。详见这里
  4. 以下是来自https://www.regex101.com的正则表达式描述:enter image description here
  5. 基本上,^匹配行的开头,\e匹配转义字符,即终端中颜色代码的起始字符,\[匹配颜色代码中的下一个字符,即[,然后(this|that)语法匹配“this”或“that”,其中“this”是32m+,即绿色的+线,而31m-是红色的-线。
  6. 颜色如下:\e[32m为绿色,\e[31m为红色。
  7. +显示由git diff标记为添加的行,当然,-则显示由git diff标记为删除的行。
  8. 请注意,在第二个grep表达式中必须使用--color=never以防止其突出显示其匹配项,否则会破坏来自左侧的来自git diff的颜色代码。
  9. \+也必须被转义为\\+,因为否则+是一个特殊的正则表达式(regex)字符,指定前一个元素的一个或多个出现。详见这里:https://en.wikipedia.org/wiki/Regular_expression#Basic_concepts

参考资料:

  1. https://git-scm.com/docs/git-diff#_combined_diff_format
  2. 回答来自@user650654:Git diff to show only lines that have been modified
  3. 回答来自@wisbucky:Git diff to show only lines that have been modified

相关内容:

  1. [我的回答] 带有行号的Git diff(带有行号的Git log)
  2. [别人的回答] 带有行号的Git diff(带有行号的Git log)
  3. 带有适当代码对齐/缩进的git diff
  4. {{link4:git-filechange-search.sh}} - 一个脚本,允许您在文件中搜索变量或函数名称,并找出包含该变量或函数名称更改的提交。例如用法:./git-filechange-search.sh path/to/my/file.cpp variable_name将查找所有包含variable_name的对file.cpp进行更改的提交。这对于查看某些功能何时发生更改很有用。就像是可以随时间观察通过git blame显示的文件部分的搜索一样。

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