可靠地“编写”Git 的关键是使用“管道”命令。
开发人员在更改管道命令时要小心,以确保它们提供非常稳定的接口(即存储库状态、标准输入、命令行选项、参数等的给定组合将在所有版本的 Git 中产生相同的输出,其中命令/选项存在)。管道命令的新输出变化可以通过新选项引入,但这不会给已经针对旧版本编写的程序引入任何问题(它们不会使用新选项,因为它们不存在(或者至少是未使用)在编写脚本时)。
不幸的是,“日常”Git 命令是“瓷器”命令,因此大多数 Git 用户可能不熟悉管道命令。瓷器和管道命令之间的区别主要在git manpage 中进行(参见标题为High-level commands (porcelain) 和Low-level commands (plumbing) 的小节。
要了解未提交的更改,您可能需要git diff-index(比较索引(可能是工作树的跟踪位)与其他一些树状结构(例如HEAD)),可能需要git diff-files(比较工作树与index),可能还有git ls-files(列出文件;例如列出未跟踪、未忽略的文件)。
(请注意,在下面的命令中,HEAD -- 被用来代替 HEAD,否则如果有一个名为 HEAD 的文件,则使用命令 fails。)
要检查存储库是否已暂存更改(尚未提交),请使用:
git diff-index --quiet --cached HEAD --
- 如果它以
0 退出,则没有差异(1 表示存在差异)。
检查工作树是否有可以暂存的更改:
git diff-files --quiet
- 退出代码与
git diff-index 相同(0 == 无差异;1 == 差异)。
检查工作树中索引和跟踪文件的组合是否相对于HEAD有变化:
git diff-index --quiet HEAD --
- 这就像前两者的组合。一个主要区别是,如果您在工作树中有“撤消”的分阶段更改(返回到
HEAD 中的内容),它仍然会报告“无差异”。在同样的情况下,两个单独的命令都会返回“存在差异”的报告。
您还提到了未跟踪的文件。您的意思可能是“未跟踪和未忽略”,或者您可能只是简单的“未跟踪”(包括被忽略的文件)。无论哪种方式,git ls-files 都是工作的工具:
对于“未跟踪”(将包括被忽略的文件,如果存在):
git ls-files --others
对于“未跟踪和未忽略”:
git ls-files --exclude-standard --others
我的第一个想法是检查这些命令是否有输出:
test -z "$(git ls-files --others)"
- 如果它以
0 退出,则没有未跟踪的文件。如果它以1 退出,则存在未跟踪的文件。
这很有可能会将来自git ls-files 的异常退出转换为“没有未跟踪的文件”报告(两者都导致上述命令的非零退出)。更强大的版本可能如下所示:
u="$(git ls-files --others)" && test -z "$u"
- 这个想法与前面的命令相同,但它允许来自
git ls-files 的意外错误传播出去。在这种情况下,非零退出可能意味着“有未跟踪的文件”或者可能意味着发生了错误。如果您希望“错误”结果与“无未跟踪文件”结果相结合,请使用test -n "$u"(其中0 的退出表示“一些未跟踪文件”,非零表示错误或“没有未跟踪文件”) .
另一个想法是在没有未跟踪的文件时使用--error-unmatch 导致非零退出。这也存在将“没有未跟踪的文件”(退出1)与“发生错误”(退出非零,但可能是128)混为一谈的风险。但是检查0 与1 与非零退出代码可能相当稳健:
git ls-files --others --error-unmatch . >/dev/null 2>&1; ec=$?
if test "$ec" = 0; then
echo some untracked files
elif test "$ec" = 1; then
echo no untracked files
else
echo error from ls-files
fi
如果您只想考虑未跟踪和未忽略的文件,则上述任何 git ls-files 示例都可以采用 --exclude-standard。