我试图列出分支历史记录中任何一点存在但随后被删除且不存在于该分支的最新提交中的所有文件的名称。
其他类似(但不相同)问题的答案表明:
git log --all --pretty=format: --name-only --diff-filter=D
Run Code Online (Sandbox Code Playgroud)
但这列出了分支历史记录中所有提交的所有单个文件删除操作,而不考虑文件是否被重新添加。
我经常使用 git ,这很危险,而且我的术语可能有点偏差,所以这里是我想要做的一个具体例子:
git init
:: add three files
echo aaa > aaa.txt
echo bbb > bbb.txt
echo ccc > ccc.txt
git add --all
git commit -m "initial commit"
:: delete aaa.txt, bbb.txt
del aaa.txt
del bbb.txt
git add --all
git commit -m "delete aaa.txt, bbb.txt"
:: re-add aaa.txt
echo zzz > aaa.txt
git add --all
git commit -m "re-add aaa.txt"
Run Code Online (Sandbox Code Playgroud)
我正在尝试弄清楚我需要列出什么命令bbb.txt- 我不在乎它aaa.txt在某个时候被删除,因为它后来被重新添加,所以它当前存在于分支的尖端。
我也不关心文件的内容,只关心“丢失”文件的名称/路径。
具体来说,我希望这个假设命令的输出为:
bbb.txt
Run Code Online (Sandbox Code Playgroud)
如果输出还可以列出“丢失”文件被删除的最新提交,这是一个额外的好处,但不是必需的。
假设是 Unix shell 环境,您可以使用commfromcoreutils将已删除文件列表与当前版本中的文件列表进行比较:
$ comm -23 \
<(git log --all --pretty=format: --name-only --diff-filter=D | sort | uniq | grep -v '^$') \
<(git ls-files | sort)
bbb.txt
Run Code Online (Sandbox Code Playgroud)
分解一下:
该comm命令逐行比较两个排序的文件。传递-23导致它只打印第一个文件中包含的行,而不打印第二个文件中包含的行。
传递到的两个“文件”comm是进程替换( <(...))。
第一个进程替换是问题中已删除文件命令的修改版本。传递输出sort | uniq以获得唯一文件路径的排序列表。输出也会被传递grep -v '^$'以删除讨厌的空行。
第二个进程替换用于git ls-files获取当前版本中所有文件的名称。这些都是sort为了保持comm快乐而排序的。
结果是历史记录中某个时刻已删除且也不包含在当前版本中的所有文件的列表。
获得已删除文件的路径后,您可以使用以下命令确定它们被删除的提交
$ git rev-list -n 1 HEAD -- <file>
Run Code Online (Sandbox Code Playgroud)
因此,要获取所有已删除的文件以及它们被删除的提交,您可以使用类似的东西
$ comm -23 \
<(git log --all --pretty=format: --name-only --diff-filter=D | sort | uniq | grep -v '^$') \
<(git ls-files | sort) \
| while IFS= read -r deleted; do
echo "$deleted" $(git rev-list -n 1 HEAD -- "$deleted");
done
bbb.txt 67e026eb45545f9d095ade3ad8f7fe9d5ad3590e
Run Code Online (Sandbox Code Playgroud)
如果您不幸遇到需要处理文件名中的-z换行符的情况,我已经验证如果您通过传递到comm、git log、sort、uniq和 来在各处使用 NUL 分隔行,这种方法仍然有效grep。