git:列出所有更改的文件,包括子模块中的文件

47

我想要获取在两个提交之间已更改的所有文件列表,包括子模块中的文件。

我知道可以执行以下操作:

git diff --name-only --diff-filter=ACMR ${revision} HEAD
它返回一个文件列表,包括子模块路径,但不包括其中的文件。
例如:我更新了一个子模块。 我提交了超级项目。 现在,我想获取所有已修改文件的列表。
你知道如何做到这一点吗?
8个回答

57

更新2017年:正如我在“在gitlab中提交子模块的差异”中提到的那样,


原始的2012年回答(Git 2.14之前)

也许一条简单的命令就足够了:

git submodule foreach --recursive git diff --name-status

那实际上会列出子模块中的子模块中的文件。
--recursive选项来自git1.7.3+)

git submodule update --remote --recursive 命令执行后,跟随 foreach diff 命令并没有显示任何内容(因为它只是在每个子模块中运行了 git diff 命令)。我们该如何查看刚刚更新的差异呢? - Zaz
我正在寻找与 OP 相同的东西,--submodule=diff 的效果非常好,但与 --name-only 结合使用时除外。我需要更改的文件,包括子模块。这是否有可能?git 版本为 2.17.1。递归也不起作用,因为我需要针对顶级仓库上的特定合并基进行检查。 - CodeMonkey
@CodeMonkey 不确定:这将是一个很好的独立问题。 - VonC
1
@CodeMonkey 明白了。这似乎确实不太方便。 - VonC
@user64204 同意。这就是CodeMonkey之前评论所暗示的。 - VonC
显示剩余4条评论

5

你可以通过使用git ls-tree找到一个子模块在给定父模块提交时的版本:

subcommit=$(git ls-tree $parentcommit $submodulepath | awk '{print $3}')

所以这里有一个脚本可以让你完成大部分工作,包括输出格式等方面:
#!/bin/sh

function compare {
    if [[ -z "$3" ]];
        then git diff --name-only --ignore-submodules=all --diff-filter=ACMR "$1" "$2"
        else git diff --name-only --ignore-submodules=all --diff-filter=ACMR "$1" "$2" | awk -v r=$3 '{ print "" r "/" $0}'
    fi

    for submodule in `git submodule | awk '{print $2}'`
    do
        old=$(git ls-tree $1 $submodule | awk '{print $3}')
        new=$(git ls-tree $2 $submodule | awk '{print $3}')
        (cd $submodule; compare $old $new $submodule)
    done
}

compare "$1" "$2"

这会输出所有类似这样的文件(尽管 Base 是子模块): HtmlTemplates/Css/Screen.css Base/Php/Classes/Helper.php

3

2017年7月8日

现在,如果您想获取包括子模块的差异,您可以使用以下命令 -

git diff --submodule=diff

注意 - 这是在 Git 2.14.0 中引入的。
“git diff --submodule=diff” 现在递归到嵌套子模块中。

是的,但当我应用--name-only时,它只显示子模块名称,所以我想要子模块内的更改文件...但不包括文件内容。 - Nikolai Ehrhardt

3
所以,这个非常简单的脚本列出了与修订版本相比的所有更改。
#!/bin/sh
echo "Listing changes for super module"
git diff $1 --name-only
subs=(`git submodule | awk '{print $2}'`)
for sub in ${subs[*]}; do
   lastrevision=`git diff  $1 $sub | fgrep "Subproject" | head -n1 | awk '{print $3}'`
   cd $sub
   echo "Listing changes for $sub"
   git diff $lastrevision --name-only
   cd ..
done

它需要一个参数 - 你想要比较的版本。 请确保使用 fgrep "Subproject",而不是 fgrep "Submodule"


谢谢。这将显示自子模块上次提交以来已更改的文件。但是,如何获取超级项目在两个版本之间已更改的所有文件(包括子模块)? - 4eyes
所以你也提交了子模块?我猜你需要一些脚本来处理... - BlacKow
1
专业提示:将此保存为“git-diff-submodules”,并使用“git diff-submodules”运行。 - Zaz
@Zaz git diff-submodules 是什么? - timblaktu

2

一个Windows版本的https://dev59.com/W2gv5IYBdhLWcg3wPORm#13169898,由Jamey Sharp创建,将是:

最初的回答。

@echo off
if NOT %1.==. goto has_rev1

@echo git diff --name-only including submodules
@echo usage:
@echo ^ ^ %~n0 ^<revision1^> [^<revision2^>^|HEAD]
@exit /b 1

:has_rev1
setlocal
set rev1=%1
if %2.==. (set rev2=HEAD) else (set rev2=%2)

call :show_diff %rev1% %rev2%
exit /b
::eof

:show_diff
setlocal ENABLEDELAYEDEXPANSION
for /f "tokens=*" %%l in ('git --no-pager diff --name-only --ignore-submodules^=all --line-prefix^=%3 %1 %2') do set fwds=%%l & set bcks=!fwds:/=\! & echo !bcks! 
endlocal
::git submodule is too slow for this
::for /f "tokens=2" %%d in ('git submodule') do call :subm %1 %2 %%d %3
if exist .gitmodules for /f "tokens=1,3*" %%p in (.gitmodules) do if %%p.==path. call :subm %1 %2 %%q %3
exit /b
::show_diff

:subm
setlocal
for /f "tokens=3" %%r in ('git ls-tree %1 %3') do set rev1=%%r
for /f "tokens=3" %%r in ('git ls-tree %2 %3') do set rev2=%%r

set fwdslash=%3
set bckslash=%fwdslash:/=\%

pushd %bckslash%
call :show_diff %rev1% %rev2% %4%bckslash%\
popd

endlocal
exit /b
::subm

"最初的回答":请注意,在子模块名称中可能需要更多的双引号才能正常工作。

1

我很惊讶没有人提到这一点,但是从v1.8.1开始,您可以这样做:

git config diff.submodule diff

现在所有的git diff命令都可以比较两个版本之间子模块内容的差异(而不仅仅是引用)。


0

我现在使用的是 git 2.32.0:

git diff --submodule=diff

并使用正则表达式模式解析输出:"--- a/(.*)"


不适用于“已重命名”。 - user64204
谢谢你的提示。 - Nikolai Ehrhardt
新添加的文件也无法工作。 - Nikolai Ehrhardt

-1

您可以使用

git -c color.diff=false diff --submodule=diff HEAD~1 HEAD | sed -n -e s/^diff\ --git\ a\\///p

只需列出您的文件列表(以HEAD~1和HEAD作为示例引用)。

我更喜欢

git -c color.diff=false diff --submodule=diff HEAD~1 HEAD | grep -E "^(diff|Submodule)\ "

按子模块对文件进行分组。根据终端的不同,使用“--no-pager”选项可能很重要,如下所示。

备注:我喜欢文件中完整彩色的差异,可以在演示后“html化”:

git -c color.diff=always --no-pager diff --submodule=diff HEAD~1 HEAD > diffFileName

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