让 git diff --stat 显示完整的文件路径

Posted

技术标签:

【中文标题】让 git diff --stat 显示完整的文件路径【英文标题】:Making git diff --stat show full file path 【发布时间】:2012-05-14 14:53:35 【问题描述】:

在执行git diff --stat 时,一些文件列出了来自存储库库的完整路径,但一些文件列出为:

.../short/path/to/filename.  

即路径以...开头,只显示短路径。

我希望git diff 列出所有文件的完整文件路径,以便脚本轻松处理它。有什么方法可以让git diff 始终显示完整路径

【问题讨论】:

【参考方案1】:

默认情况下,git diff 会截断其输出以适应 80 列终端。

您可以通过使用--stat option 指定值来覆盖它:

--stat[=<width>[,<name-width>[,<count>]]]
       Generate a diffstat. You can override the default output width for
       80-column terminal by --stat=<width>. The width of the filename
       part can be controlled by giving another width to it separated by a
       comma. By giving a third parameter <count>, you can limit the
       output to the first <count> lines, followed by ...  if there are
       more.

       These parameters can also be set individually with
       --stat-width=<width>, --stat-name-width=<name-width> and
       --stat-count=<count>.

例如,通过将输出值设置为一个非常大的数字:

git diff --stat=10000

请注意,它会生成相对于 git 存储库根目录的路径。

(对于脚本,你可能想直接使用git diff-tree,因为它更像是一个“管道”命令,尽管我怀疑你会很好。请注意,使用时你需要与--stat 相同的额外文本git diff-tree. 使用git diff“porcelain”前端和git diff-tree 管道命令之间的本质区别在于git diff 查找您配置的设置以查找diff.renames 等选项以决定是否进行重命名检测. 好吧,加上前端git diff 将相当于git diff-index,例如,如果您将提交与索引进行比较。换句话说,git diff 读取您的配置 并且自动调用正确的管道。)

【讨论】:

git diff --numstat 和 diff-tree 一样 请注意,要限制最后一部分的宽度 (+++/---),您可以使用单独的 --stat-graph-width=... 开关。另请注意,将--stat-graph-width=--stat-name-width= 设置得高是不够的,您还必须将--stat-width= 设置得足够大以覆盖两者。 @jakub.g:好点。基于对 git 源代码的一些挖掘,这与 git 1.7.10 一起使用。 有没有办法全球化?每次都打字太疯狂了。 @Rudie:唉,不:有一个配置变量 diff.statGraphWidth 可以用来设置 --stat-graph-width 值,但其他默认为您的终端宽度。 (所以,替代答案:“是的,只需将您的终端窗口设为 1000 列宽”:-))【参考方案2】:

对于脚本处理,最好使用以下方法之一:

# list just the file names
git diff --name-only
path/to/modified/file
path/to/renamed/file


# list the names and change statuses:
git diff --name-status
M       path/to/modified/file
R100    path/to/existing/file   path/to/renamed/file


# list a diffstat-like output (+ed lines, -ed lines, file name):
git diff --numstat
1       0       path/to/modified/file
0       0       path/to/existing => renamed/file

当与使用NUL 作为字段终止符的-z 选项结合使用时,这些都变得更便于进行健壮的脚本处理。

【讨论】:

根据我的测试,您不会使用这些命令收到资源的完整路径。现在我只看到已删除文件的相对路径。不知道是不是只有这些文件才有这种情况。 所有输出都将返回相对于git rev-parse --show-toplevel 的路径。最初的问题是指截断的路径,这是 diffstats 中的一个问题,特别是对于长文件名或 --stat-name-width 的低值。上面的命令不会截断路径,但会根据请求显示“完整”路径,尽管它仍然相对于存储库根目录。【参考方案3】:

对于 Bash 用户,您可以使用 $COLUMNS 变量来自动填充可用的终端宽度:

git diff --stat=$COLUMNS

很长的路径名可能仍会被截断;在这种情况下,您可以使用 --stat-graph-width 减小 +++/--- 部分的宽度,例如这会将其限制为终端宽度的 1/5:

git show --stat=$COLUMNS --stat-graph-width=$(($COLUMNS/5))

对于更通用的解决方案,您可以使用tput cols 的输出来确定终端宽度。

【讨论】:

有没有办法全球化--stat=$COLUMNS,$COLUMNS?每次都打字太疯狂了。 @Rudie 将export COLUMNS 添加到您的~/.bashrc,并在您的~/.gitconfig 中的[alias] 下添加smart-diff = ! "gitsmartdiff() git diff $2 --stat=$COLUMNS,$COLUMNS; ; gitsmartdiff" @user151841 这只会改变diff。我希望它也适用于合并和拉取等。 (甚至不能在那里手动完成。)我认为 GIT 不支持它。 @Rudie 好吧,在拉取或合并完成后,您可以区分以前的哈希值和新的哈希值。 @user151841 当然可以,但是合并已经给出了统计摘要。没有参数/配置。如果所有“统计摘要”都使用相同的配置,那就太好了。【参考方案4】:

有一个选项--name-onlygit diff --name-only。其他 git 命令也支持该选项,例如 showstash

该选项不会缩短路径。

【讨论】:

git diff-tree 也有相应的选项,但您还需要指定其他选项,例如 git diff-tree --name-only -r --no-commit-id HEAD。请参阅我的回答 ***.com/a/67330880/1507124 了解更多信息【参考方案5】:

我发现一个简单的解决方案是这样做:(仅适用于 *nix,抱歉没有 osx)

git diff --stat=$COLUMNS --relative | head -n -1 | cut -c 2- | xargs -d '\n' -P4 printf "$(pwd)/%s\n"

此版本适用于两者,但在 osx 上看起来不太好。

git diff --stat=$COLUMNS --relative | sed -e '$ d' | cut -c 2- | xargs -n4 -I echo "$(pwd)/"

【讨论】:

我发现仅仅使用--relative 对我帮助很大。 (我已经使用了--stat 宽度选项。【参考方案6】:

我创建了以下 git 别名:

diffstat = ! "gitdiffstat()   git diff --stat=$(tput cols) $1:-master ; ; gitdiffstat"

它从tput cols 命令读取列数。它默认与master 进行比较,但您可以选择指定另一个分支。

$ git diffstat
 .gitalias | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

【讨论】:

【参考方案7】:

git diff 是一个瓷器(用户友好)命令。出于脚本目的,您可能希望使用相应的管道命令git diff-tree

您可以使用--name-only-r--no-commit-id 选项的组合,让git diff-tree 输出相对于git 存储库的完整路径。

示例

在当前分支的“最后”(HEAD)提交中更改的文件路径。

git diff-tree --name-only -r --no-commit-id HEAD

main 分支上最后一次提交中的文件路径

git diff-tree --name-only -r --no-commit-id main

main 分支上最后三个​​提交的文件路径

git diff-tree --name-only -r main main~3

路径src/下最后一次提交的文件路径

git diff-tree --name-only -r --no-commit-id main src/

在当前分支的最后一次提交中更改的文件的绝对路径

git diff-tree --name-only -r --no-commit-id --line-prefix=`git rev-parse --show-toplevel`/ HEAD

说明

git diff-tree 比较两个 treeish 对象的 blob

提交是一个treeish 对象,它指向存储库根目录中的对象。目录也是treeish 对象,而文件是blobs

运行git diff-tree HEAD 将比较HEADHEAD~1 的blob,并包含存储库根的blob 差异。要查看所有不在根目录中的已更改文件,我们需要进入目录treeish 对象。这是使用-r(如递归)选项实现的。

请注意,这允许在任意提交中一二比较任意目录。

默认情况下,如果只指定了一个 commit 对象,则会将其与其父对象进行比较。即,运行git diff-tree HEAD 等价于git diff-tree HEAD HEAD~1。如果您仅将一个提交指定为 treeish 对象,则会显示父提交 ID。使用--no-commit-id 可以解决这个问题。

git-diff-tree 打印出很多我们不想要的信息(id、权限、是否是添加、删除、修改)。我们只想要名字,所以我们使用--name-only

如果我们想要绝对路径,我们需要使用类似git rev-parse --show-toplevel 之类的东西为所有行添加前缀。这将获取存储库的绝对路径,没有尾随 /。所以我们添加了它。

--line-prefix=`git rev-parse --show-toplevel`/

【讨论】:

【参考方案8】:

我发现 diff --stat 的行为在 git 1.7.10 附近发生了变化,以前它默认将文件路径缩短到固定宽度 - 现在它显示的内容与终端窗口允许的一样多。如果您遇到此问题,请确保升级到 1.8.0 或更高版本。

【讨论】:

以上是关于让 git diff --stat 显示完整的文件路径的主要内容,如果未能解决你的问题,请参考以下文章

Git:显示两次提交之间的总文件大小差异?

git diff

如何获得完整上下文的 git diff?

git diff使用简单记录

git diff使用简单记录

能否在所有git项目中,让所有的 "git diff "命令都使用 "Python diff"?