从 `git ls-files` 中排除暂存为已删除的文件

Exclude files staged as deleted fom `git ls-files`

我在脚本中使用 git ls-files 来收集 git 跟踪的所有文件。不幸的是,如果你 rm 一个文件(而不是 git rm)它不再存在于文件系统中,但它仍然会被 git ls-files

列出

所以问题是:有没有一种简单有效的方法可以从中排除文件系统中不再存在的文件git ls-files 输出本身或之后过滤它(使用例如 bash)?像

git ls-files --existing-only

背景:我想创建一个 CMake 虚拟目标,它包含属于项目目录的 所有 文件(即由 git 跟踪)。我使用类似

execute_process(
    COMMAND bash -c "cd ${CMAKE_SOURCE_DIR}; git ls-files"
    OUTPUT_VARIABLE ADDITIONAL_PROJECT_FILES
)

生成文件列表。但不幸的是,rm正在处理文件但尚未暂存更改将导致错误,因为 CMake 无法再找到该文件..

更新:在我进行编辑之前,我正在谈论 git rm 一个文件 - git ls-files 将正确处理该文件。但问题仍然存在:如果有人删除了一个文件(没有使用 git),git ls-files 将列出它(我 运行 陷入困境)。

我不认为你可以用 git ls-files 本身来做到这一点(有点遗憾,因为它对这类事情非常方便)。

最终,对于 Git,work-tree 中不存在文件这一事实对于下一次提交并不重要。提交使用索引 / staging-area 中的任何内容。 git ls-files 的主要焦点是索引内容,因此 --stage--debug 等选项。然而,--others选项的存在证明git ls-files可以扫描work-tree。扫描 work-tree 后,它可以向您显示哪些文件在 work-tree 中但在索引中缺失:--others。这个列表可以进一步subtracted-away-from,使用--exclude-standard之类的

你的特殊情况是,不是获取 work-tree 个文件的列表,而是减去 的文件在 index 中,您想获取 index 文件的列表并减去那些 不是 [=58] 的文件=] 在 work-tree 中。也就是说,如果我们将 I 定义为索引文件集,将 W 定义为 work-tree 文件集,我们会看到git ls-files可以轻松计算出W\I。我们想让它计算 I\W,索引中但在 work-tree 中缺失的文件集,以便我们可以从 git ls-files的输出。

唉,没有这样的选择。剩下 git diff-files,它可以轻松计算这组文件:git diff-files --name-only --diff-filter=D HEAD 为您提供索引中但在 work-tree 中丢失的文件。使用 这个 列表从 git ls-files 输出中删除文件名,你就有了你需要的。

重要侧边栏

通常,work-tree 中缺少但存在于索引中的文件错误地处于这种状态,正确的做法是将它们从索引中提取到 work-tree。此外,任何时候您打算对索引中的文件集执行某些操作时,您都应该考虑到 work-tree[=56= 中这些文件的副本这一事实] 可能与索引中的副本 不同 。例如,Git pre-commit 挂钩可能旨在确保文件针对某些源语言正确格式化:运行 通过 clang-formatblack 会让它们保持不变,例如。

通过检查 work-tree 文件对此进行测试从根本上来说是错误的,因为 Git 不会从 [=75] 构建提交=].这意味着这些工具应该将整个索引提取到 临时(新的和空的)work-tree 文件系统中的其他地方,然后 运行 格式化程序,或任何要在该临时 work-tree 上使用的工具。此过程的结果告诉您是否应继续提交。然后删除临时 work-tree(即,自己清理)并提供适当的 "can commit" / "no, don't commit" 退出状态。

comm -23 <(git ls-files --modified | sort) <(git ls-files --deleted | sort)

来自comm --help

  -2              suppress column 2 (lines unique to FILE2)
  -3              suppress column 3 (lines that appear in both files)