我如何检查我的git存储库中是否有任何未提交的更改:

添加到索引但未提交的更改 无路径的文件

从一个脚本?

git-status在git 1.6.4.2版本中似乎总是返回0。


当前回答

看了一下这些答案…(在*nix和windows上有各种问题,这是我的要求)…发现以下方法效果很好…

git diff --no-ext-diff --quiet --exit-code

检查*nix中的退出代码

echo $?   
#returns 1 if the repo has changes (0 if clean)

查看窗口$中的退出代码

echo %errorlevel% 
#returns 1 if the repos has changes (0 if clean) 

来源:https://github.com/sindresorhus/pure/issues/115 感谢@paulirish的分享

其他回答

可靠地“脚本化”Git的关键是使用“管道”命令。

The developers take care when changing the plumbing commands to make sure they provide very stable interfaces (i.e. a given combination of repository state, stdin, command line options, arguments, etc. will produce the same output in all versions of Git where the command/option exists). New output variations in plumbing commands can be introduced via new options, but that can not introduce any problems for programs that have already been written against older versions (they would not be using the new options, since they did not exist (or at least were not used) at the time the script was written).

不幸的是,“日常”Git命令是“瓷器”命令,所以大多数Git用户可能不熟悉管道命令。瓷器和管道命令之间的区别是在git的主要manpage中做出的(参见高级命令(瓷器)和低级命令(管道)的子章节。


要找出未提交的更改,你可能需要git diff-index(比较索引(可能是工作树的跟踪位)和一些其他树(例如HEAD)),可能是git diff-files(比较工作树和索引),可能是git ls-files(列表文件;例如,列出未跟踪、未忽略的文件)。

(注意,在下面的命令中,使用HEAD——而不是HEAD,否则如果有一个名为HEAD的文件,命令就会失败。)

要检查存储库是否有阶段性更改(尚未提交),请使用以下命令:

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都是完成这项工作的工具:

对于“untracked”(将包括被忽略的文件,如果存在):

git ls-files --others

对于“untracked and unignored”:

git ls-files --exclude-standard --others

我的第一个想法是检查这些命令是否有输出:

test -z "$(git ls-files --others)"

如果它以0退出,则没有未跟踪的文件。如果它以1退出,则存在未跟踪的文件。

这有很小的可能会将git ls-files中的异常退出转换为“no untracked files”报告(两者都会导致上述命令的非零退出)。更健壮的版本可能是这样的:

u="$(git ls-files --others)" && test -z "$u"

这个想法与前面的命令相同,但是它允许来自git ls-files的意外错误传播出去。在这种情况下,非零退出可能意味着“有未跟踪的文件”,也可能意味着发生了错误。如果你想要“error”结果与“no untracked files”结果相结合,使用test -n "$u"(其中exit为0表示“一些未跟踪的文件”,non- 0表示错误或“no untracked files”)。

另一种想法是使用——error-unmatch在没有未跟踪文件时导致非零退出。这也存在将“没有未跟踪文件”(退出1)与“发生错误”(退出非零,但可能是128)混为一谈的风险。但是检查0、1和非0退出码可能相当健壮:

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。

为什么不封装'git状态与一个脚本:

将分析该命令的输出 是否会根据需要返回适当的错误代码

这样,您就可以在脚本中使用“增强”状态。


正如0xfe在他的精彩回答中提到的,git状态—瓷器在任何基于脚本的解决方案中都是重要的

--porcelain

为脚本提供稳定、易于解析的输出格式。 目前这与——short输出相同,但保证将来不会更改,因此对脚本是安全的。

假设你使用的是git 1.7.0或更高版本…

在阅读了本页上的所有答案并进行了一些实验后,我认为将正确性和简洁性正确结合的方法是:

test -n "$(git status --porcelain)"

虽然git允许在跟踪、忽略、未跟踪但未忽略等内容之间有很多细微差别,但我相信典型的用例是用于自动化构建脚本,如果签出不干净,您希望停止所有内容。

在这种情况下,模拟程序员将要做的事情是有意义的:键入git status并查看输出。但我们不想依赖于特定的单词显示,所以我们使用了1.7.0中引入的——porcelain模式;启用干净目录时,不会产生任何输出。

然后使用test -n查看是否有输出。

如果工作目录是干净的,该命令将返回1,如果有要提交的更改,则返回0。你可以把-n改成-z。这对于将其链接到脚本中的命令非常有用。例如:

test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"

这实际上是在说“要么不需要做出改变,要么就会拉响警报”;这个一行语句可能比if语句更可取,这取决于您正在编写的脚本。

我经常需要一种简单的方法让构建失败,如果在执行结束时有任何被修改的跟踪文件或任何未被忽略的未跟踪文件。

这对于避免构建产生剩余的情况非常重要。

到目前为止,我使用的最好的命令是这样的:

 test -z "$(git status --porcelain | tee /dev/fd/2)" || \
     {{ echo "ERROR: git unclean at the end, failing build." && return 1 }}

它可能看起来有点复杂,如果有人能找到一个短的变种,我会很感激 保持所期望的行为:

如果一切正常,则没有输出和成功退出代码 如果失败,退出代码1 stderr上的错误消息解释了它失败的原因 显示导致失败的文件列表,再次stderr。

你也可以

git describe --dirty

. 如果它检测到一个肮脏的工作树,它将在结尾附加单词“-dirty”。根据git-describe(1):

   --dirty[=<mark>]
       Describe the working tree. It means describe HEAD and appends <mark> (-dirty by default) if
       the working tree is dirty.

. 注意:未跟踪的文件不被认为是“脏文件”,因为,正如manpage声明的那样,它只关心工作树。