如何获取带有完整上下文的git diff?

158

我该如何创建一个带有完整上下文的补丁?

我尝试了 --unified=2000,它会提供2000行上下文:

git diff --unified=2000 branch master --no-prefix > patch

如何在不指定最大行数的情况下包含文件中的所有行?


4
我将在此链接中发布-U<infinity>选项作为单独的问题,以显示整个文件 https://dev59.com/Sl4b5IYBdhLWcg3wvkA- - Aleksandr Levchuk
7个回答

133

这个 看起来非常不错:

git diff --no-prefix -U1000

有一个注意点:

-U 标志指定上下文的行数。如果您的更改之间的行数超过1000行,则可能需要增加此值。


30
你建议的 -U 选项与提问者使用的 --unified= 选项相同,唯一的区别是你指定的上下文行数较少,只有1000行,而提问者使用的是2000行。@balki 想知道如何将行数增加到无限大,但你建议将行数减半。为什么? - Mr. Lance E Sloan
6
是的,我现在意识到了,但是几年前我忽略了这一点。不过,比起问题来,现在情况更加明显,似乎对于那些来到这里的人有所帮助。 - c24w
谢谢,这个方法在使用 git show 时也非常好用! - Shakeel
但它根本没有回答问题,即“有没有办法告诉git在补丁中包含文件中的所有行,而无需指定最大行数?” - flying sheep
3
--no-prefix选项可以去除默认情况下出现的“/a/”和“/b/”目标路径前缀。(链接页面) - luckydonald

79

我知道这已经很老了,但我也不喜欢硬编码的解决方案,所以我测试了一下:

git diff -U$(wc -l MYFILE)

使用-U似乎是解决该问题的唯一方法,但使用行数承诺即使在非常大的文件中进行小改动也可以正常工作。


1
< is not necessary. git diff -U$(wc -l MYFILE) MYFILE - balki
3
谢谢@balki,我尝试了您的建议并注意到<pre>$(wc -l MYFILE)</pre>会扩展为行数和文件名,因此第二次使用文件名也可以省略。 我正在更新我的回答以反映这一点。 - Ezra
13
这是一个diff,有两个版本的文件。如果磁盘上没有的那个版本是原来长度的两倍,使用一个非常大的数字作为-U参数会更安全吗? - Eloff
1
我们可以从这个答案中找到一些灵感来实现一个shell计算的最大值:https://unix.stackexchange.com/a/186703 - 在我看来,用户可能会将其作为别名放入他们的git配置文件中,因此冗长的命令是可以接受的。理想情况下,git应该内置一个--full-context diff选项。 - Ezra
7
git diff -U$(wc -l MYFILE | awk '{print $1}') MYFILE 是更好的答案,它通过获取不包含空白行的行数来正确解析 wc 的输出,而不是依靠未加引号的子 shell 输出创建两个参数,并且适用于 macOS/BSD。 - anishpatel
显示剩余2条评论

11
注意:git1.8.1rc1公告(2012年12月8日)包括:

一个名为"diff.context"的新配置变量可用于在修补程序输出中提供默认上下文行数,以覆盖硬编码默认的3行。

因此,这可以帮助生成更完整的上下文。


8
然而,这并没有选项可以说“文件中的所有行”。 - balki
3
我怀疑把一个大数值放在那里,以模拟“所有的行”。 - VonC
7
我猜测,把一个很大的数字放进去,可以模拟“所有行”的情况,但有时会出现问题导致程序崩溃。 “所有”可以理解为无限,而“很大的数字”只是一个数字,不是无限。 - Trenton

5

受到灵感的启发,我添加了一个Git别名。

$ cat ~/.gitconfig | fgrep diff
        df = "!git diff -U$(wc -l \"$1\" | cut -d ' ' -f 1) \"$1\""
$ git df <file>

更新:

刚刚发现 git df 有时无法工作,原因是执行 git 别名时目录发生了变化 (详见git aliases operate in the wrong directory)。此外,@Moises Soto 在 macOS 上提到 wc 命令的输出格式不同(wc -l 输出前面有6个空格),建议使用 awk。因此这是更新后的版本:

$ cat ~/.gitconfig | fgrep df
        df = "! [ \"$GIT_PREFIX\" != \"\" ] && cd \"$GIT_PREFIX\"; ~/bin/git_df.sh"
$ 
$ cat ~/bin/git_df.sh
#!/bin/bash
for FILE in $@; do
    git diff -U$(wc -l "${FILE}" | awk '{print $1}') "${FILE}"
done
exit 0

对于单行别名:df =“!cd -- $ {GIT_PREFIX:-。}; git diff -U $(wc -l \”$ 1 \“| cut -d' ' -f 1)\”$ 1 \“” - fizzyh2o
@fizzyh2o,是的,如果git df只有一个文件,你的版本也可以工作,但是我的版本支持git df多个文件。 - Yun Wu

2

2

我只是使用

git diff -W Git.md

列出文件的完整路径。来自man git diff:

-W,--function-context
显示每个更改的整个函数作为上下文行。


这是一个值得了解的相关开关,然而它并不一定包含整个文件(大多数文件都会有多个功能)。 - David Cook

-1

之前接受的解决方案在查看特定文件/提交时对我不起作用(-U选项似乎会影响版本/路径解析),但是在git version 2.24.0上,--inter-hunk-context=在这种情况下有效:

git diff \
    --no-prefix \
    --inter-hunk-context=2000 \
    master -- \
        path/to/file.py

如果您不知道文件大小,当然可以使用wc -l来查找它,而不是硬编码它:

git diff \
    --no-prefix \
    --inter-hunk-context=$(wc -l path/to/file.py) \
    master -- \
        path/to/file.py

对我来说,这只显示第一个更改之前的三行上下文和最后一个更改之后的三行上下文。 - ma11hew28
你使用的是哪个版本的git?你是否将"path/to/file.py"替换为自己的文件路径?我在Windows上测试了(第一个硬编码变体),使用的是git 2.12.1,它完全正常。 - stefco
版本2.24.3。是的,我做了。但抱歉,让我澄清一下我的最后一条评论:您的解决方案当然也显示了所有更改行之间(包括更改行),但我认为@Machavity想要“包含文件中的所有行”。例如,在至少有五行并且在第四行之后进行所有更改的文件上尝试您的解决方案。如果它所显示的内容包括文件的第一行,那么也许您的Git配置文件中的'diff.context'变量设置为大于默认值3的数字。 - ma11hew28

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