使用 Git 检查脏索引或未跟踪的文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2657935/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Checking for a dirty index or untracked files with Git
提问by Robert Munteanu
How can I check if I have any uncommitted changes in my git repository:
如何检查我的 git 存储库中是否有任何未提交的更改:
- Changes added to the index but not committed
- Untracked files
- 添加到索引但未提交的更改
- 未跟踪的文件
from a script?
从脚本?
git-status
seems to always return zero with git version 1.6.4.2.
git-status
git 版本 1.6.4.2 似乎总是返回零。
采纳答案by 0xfe
Great timing! I wrote a blog post about exactly this a few days ago, when I figured out how to add git status information to my prompt.
好时机!几天前我写了一篇关于这个的博客文章,当时我想出了如何将 git 状态信息添加到我的提示中。
Here's what I do:
这是我所做的:
For dirty status:
# Returns "*" if the current git branch is dirty. function evil_git_dirty { [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*" }
For untracked files (Notice the
--porcelain
flag togit status
which gives you nice parse-able output):# Returns the number of untracked files function evil_git_num_untracked_files { expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l` }
对于脏状态:
# Returns "*" if the current git branch is dirty. function evil_git_dirty { [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*" }
对于未跟踪的文件(请注意为您提供了很好的可解析输出的
--porcelain
标志git status
):# Returns the number of untracked files function evil_git_num_untracked_files { expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l` }
Although git diff --shortstat
is more convenient, you can also use git status --porcelain
for getting dirty files:
虽然git diff --shortstat
更方便,但您也可以git status --porcelain
用于获取脏文件:
# Get number of files added to the index (but uncommitted)
expr $(git status --porcelain 2>/dev/null| grep "^M" | wc -l)
# Get number of files that are uncommitted and not added
expr $(git status --porcelain 2>/dev/null| grep "^ M" | wc -l)
# Get number of total uncommited files
expr $(git status --porcelain 2>/dev/null| egrep "^(M| M)" | wc -l)
Note: The 2>/dev/null
filters out the error messages so you can use these commands on non-git directories. (They'll simply return 0
for the file counts.)
注意:2>/dev/null
过滤掉错误消息,以便您可以在非 git 目录上使用这些命令。(他们只会返回0
文件计数。)
Edit:
编辑:
Here are the posts:
以下是帖子:
Adding Git Status Information to your Terminal Prompt
回答by Chris Johnsen
The key to reliably “scripting” Git is to use the ‘plumbing' commands.
可靠地“编写”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 中产生相同的输出,其中命令/选项存在)。管道命令中的新输出变化可以通过新选项引入,但这不会给已经针对旧版本编写的程序带来任何问题(他们不会使用新选项,因为它们不存在(或至少是未使用)在编写脚本时)。
Unfortunately the ‘everyday' Git commands are the ‘porcelain' commands, so most Git users may not be familiar with with the plumbing commands. The distinction between porcelain and plumbing command is made in the main git manpage(see subsections titled High-level commands (porcelain)and Low-level commands (plumbing).
不幸的是,“日常”Git 命令是“瓷器”命令,因此大多数 Git 用户可能不熟悉管道命令。瓷器和管道命令之间的区别在主git 联机帮助页中进行了(请参阅标题为高级命令(瓷器)和低级命令(管道)的小节)。
To find out about uncomitted changes, you will likely need git diff-index
(compare index (and maybe tracked bits of working tree) against some other treeish (e.g. HEAD
)), maybe git diff-files
(compare working tree against index), and possibly git ls-files
(list files; e.g. list untracked, unignored files).
要找出未提交的更改,您可能需要git diff-index
(将索引(可能是工作树的跟踪位)与其他树状(例如HEAD
)git diff-files
进行比较),可能(将工作树与索引进行比较),并且可能git ls-files
(列出文件;例如列出未跟踪的, 未忽略的文件)。
(Note that in the below commands, HEAD --
is used instead of HEAD
because otherwise the command failsif there is a file named HEAD
.)
(请注意,在下面的命令中,HEAD --
使用 代替HEAD
因为如果存在名为 的文件,则命令将失败HEAD
。)
To check whether a repository has staged changes (not yet committed) use this:
要检查存储库是否已暂存更改(尚未提交),请使用以下命令:
git diff-index --quiet --cached HEAD --
- If it exits with
0
then there were no differences (1
means there were differences).
- 如果它退出,
0
则没有差异(1
意味着存在差异)。
To check whether a working tree has changes that could be staged:
要检查工作树是否具有可以暂存的更改:
git diff-files --quiet
- The exit code is the same as for
git diff-index
(0
== no differences;1
== differences).
- 退出代码与
git diff-index
(0
== 无差异;1
== 差异)相同。
To check whether the combination of the index and the tracked files in the working tree have changes with respect to HEAD
:
要检查索引和工作树中被跟踪文件的组合是否在以下方面发生了变化HEAD
:
git diff-index --quiet HEAD --
- This is like a combination of the previous two. One prime difference is that it will still report “no differences” if you have a staged change that you have “undone” in the working tree (gone back to the contents that are in
HEAD
). In this same situation, the two separate commands would both return reports of “differences present”.
- 这就像前两者的结合。一个主要区别是,如果您在工作树中“撤消”了一个分阶段的更改(回到 中的内容
HEAD
),它仍然会报告“没有差异” 。在同样的情况下,两个单独的命令都会返回“存在差异”的报告。
You also mentioned untracked files. You might mean “untracked and unignored”, or you might mean just plain “untracked” (including ignored files). Either way, git ls-files
is the tool for the job:
您还提到了未跟踪的文件。您的意思可能是“未跟踪和未忽略”,或者您的意思可能只是简单的“未跟踪”(包括被忽略的文件)。无论哪种方式,git ls-files
都是这项工作的工具:
For “untracked” (will include ignored files, if present):
对于“未跟踪”(将包括被忽略的文件,如果存在):
git ls-files --others
For “untracked and unignored”:
对于“未跟踪和未忽略的”:
git ls-files --exclude-standard --others
My first thought is to just check whether these commands have output:
我的第一个想法是检查这些命令是否有输出:
test -z "$(git ls-files --others)"
- If it exits with
0
then there are no untracked files. If it exits with1
then there are untracked files.
- 如果它退出,
0
则没有未跟踪的文件。如果它退出,1
则存在未跟踪的文件。
There is a small chance that this will translate abnormal exits from git ls-files
into “no untracked files” reports (both result in non-zero exits of the above command). A bit more robust version might look like this:
这极有可能会将异常退出git ls-files
转换为“无未跟踪文件”报告(两者都会导致上述命令的退出非零)。更强大的版本可能如下所示:
u="$(git ls-files --others)" && test -z "$u"
- The idea is the same as the previous command, but it allows unexpected errors from
git ls-files
to propagate out. In this case a non-zero exit could mean “there are untracked files” or it could mean an error occurred. If you want the “error” results combined with the “no untracked files” result instead, usetest -n "$u"
(where exit of0
means “some untracked files”, and non-zero means error or “no untracked files”).
- 这个想法与前面的命令相同,但它允许意外错误
git ls-files
传播出去。在这种情况下,非零退出可能意味着“有未跟踪的文件”或者可能意味着发生了错误。如果您希望将“错误”结果与“无未跟踪文件”结果相结合,请使用test -n "$u"
(其中退出0
表示“某些未跟踪文件”,非零表示错误或“无未跟踪文件”)。
Another idea is to use --error-unmatch
to cause a non-zero exit when there are no untracked files. This also runs the risk of conflating “no untracked files”?(exit 1
) with “an error occurred” (exit non-zero, but probably 128
). But checking for 0
vs. 1
vs. non-zero exit codes is probably fairly robust:
另一个想法是--error-unmatch
在没有未跟踪文件时使用导致非零退出。这也存在将“没有未跟踪的文件”?(退出1
)与“发生错误”(退出非零,但可能128
)混淆的风险。但是检查0
vs. 1
vs. 非零退出代码可能相当健壮:
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
Any of the above git ls-files
examples can take --exclude-standard
if you want to consider only untracked and unignored files.
如果您只想考虑未跟踪和未忽略的文件,则git ls-files
可以采用上述任何示例--exclude-standard
。
回答by benzado
Assuming you are on git 1.7.0 or later...
假设您使用的是 git 1.7.0 或更高版本...
After reading all of the answers on this page and some experimenting, I think the method that hits the right combination of correctness and brevity is:
在阅读了本页上的所有答案并进行了一些实验后,我认为正确结合正确性和简洁性的方法是:
test -n "$(git status --porcelain)"
While git allows for a lot of nuance between what's tracked, ignore, untracked but unignored, and so on, I believe the typical use case is for automating build scripts, where you want to stop everything if your checkout isn't clean.
虽然 git 允许在跟踪、忽略、未跟踪但未忽略等之间存在很多细微差别,但我相信典型的用例是自动化构建脚本,如果您的结帐不干净,您希望停止一切。
In that case, it makes sense to simulate what the programmer would do: type git status
and look at the output. But we don't want to rely on specific words showing up, so we use the --porcelain
mode introduced in 1.7.0; when enabled, a clean directory results in no output.
在这种情况下,模拟程序员会做什么是有意义的:键入git status
并查看输出。但是我们不想依赖特定的单词出现,所以我们使用--porcelain
1.7.0中引入的模式;启用后,干净的目录不会产生任何输出。
Then we use test -n
to see if there was any output or not.
然后我们test -n
用来查看是否有任何输出。
This command will return 1 if the working directory is clean and 0 if there are changes to be committed. You can change the -n
to a -z
if you want the opposite. This is useful for chaining this to a command in a script. For example:
如果工作目录是干净的,则此命令将返回 1,如果要提交更改,则返回 0。如果您想要相反的情况-n
,您可以将 the 更改为 a -z
。这对于将其链接到脚本中的命令很有用。例如:
test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"
This effectively says "either there are no changes to be made or set off an alarm"; this one-liner might be preferable to an if-statement depending on the script you are writing.
这实际上是说“要么没有改变,要么触发警报”;根据您正在编写的脚本,这种单行语句可能比 if 语句更可取。
回答by Dean Rather
回答by mlo55
Had a look through a few of these answers... (and had various issues on *nix and windows, which was a requirement I had)... found the following worked well...
浏览了其中的一些答案......(并且在 *nix 和 windows 上有各种问题,这是我的要求)......发现以下效果很好......
git diff --no-ext-diff --quiet --exit-code
To check the exit code in *nix
检查 *nix 中的退出代码
echo $?
#returns 1 if the repo has changes (0 if clean)
To check the exit code in window$
检查 window$ 中的退出代码
echo %errorlevel%
#returns 1 if the repos has changes (0 if clean)
Sourced from https://github.com/sindresorhus/pure/issues/115Thanks to @paulirish on that post for sharing
来自https://github.com/sindresorhus/pure/issues/115感谢@paulirish 在该帖子上的分享
回答by Robert Munteanu
One DIY possibility, updated to follow 0xfe's suggestion
一种 DIY 可能性,已更新以遵循0xfe的建议
#!/bin/sh
exit $(git status --porcelain | wc -l)
As noted by Chris Johnsen, this only works on Git 1.7.0 or newer.
正如Chris Johnsen所指出的,这仅适用于 Git 1.7.0 或更新版本。
回答by VonC
Why not encapsulate 'git status
with a script which:
为什么不用git status
脚本封装 ' :
- will analyze the output of that command
- will return the appropriate error code based on what you need
- 将分析该命令的输出
- 将根据您的需要返回适当的错误代码
That way, you can use that 'enhanced' status in your script.
这样,您就可以在脚本中使用“增强”状态。
As 0xfementions in his excellent answer, git status --porcelain
is instrumental in any script-based solution
作为0xFE的他提到了出色的答案,git status --porcelain
在任何基于脚本的解决方案工具
--porcelain
Give the output in a stable, easy-to-parse format for scripts.
Currently this is identical to--short output
, but is guaranteed not to change in the future, making it safe for scripts.
以稳定、易于解析的格式为脚本提供输出。
目前这与 相同--short output
,但保证将来不会更改,使其对脚本安全。
回答by sorin
I needed quite often a simple way to fail a build if at the end of execution there are any modified tracked files or any untracked files that are not ignored.
如果在执行结束时有任何修改的跟踪文件或任何未被忽略的未跟踪文件,我经常需要一种简单的方法来使构建失败。
This is quite important for avoiding case where builds produce leftovers.
这对于避免构建产生剩余物的情况非常重要。
So far, the best command I ended up using looks like:
到目前为止,我最终使用的最佳命令如下所示:
test -z "$(git status --porcelain | tee /dev/fd/2)" || \
{{ echo "ERROR: git unclean at the end, failing build." && return 1 }}
It may look bit complex and I would appreciate if anyone finds a shorted variant that this maintains desired behavior:
它可能看起来有点复杂,如果有人发现可以保持所需行为的短路变体,我将不胜感激:
- no output and succcess exit code if evenything is in order
- exit code 1 if it fails
- error message on stderr explaining why it fails
- display list of files causing the failure, stderr again.
- 如果一切正常,则没有输出和成功退出代码
- 如果失败,退出代码 1
- stderr 上的错误消息解释了它失败的原因
- 再次显示导致失败的文件列表,stderr。
回答by oliver
@eduard-wirch answer was quite complete, but as I wanted to check both at the same time, here is my final variant.
@eduard-wirch 的回答非常完整,但由于我想同时检查两者,这是我的最终变体。
set -eu
u="$(git ls-files --others)"
if ! git diff-index --name-only --quiet HEAD -- || [ -z "${u:-}" ]; then
dirty="-dirty"
fi
When not executing using set -e or equivalent, we instead can do an u="$(git ls-files --others)" || exit 1
(or return if this works for a used function)
当不使用 set -e 或等价物执行时,我们可以执行 an u="$(git ls-files --others)" || exit 1
(如果这适用于使用过的函数,则返回)
So untracked_files, is only set if the command succeeds properly.
所以 untracked_files, 只有在命令正确成功时才设置。
after which, we can check for both properties, and set a variable (or whatever).
之后,我们可以检查这两个属性,并设置一个变量(或其他)。
回答by Linus Arver
You can also do
你也可以这样做
git describe --dirty
. It will append the word "-dirty" at the end if it detects a dirty working tree. According to git-describe(1)
:
. 如果检测到脏工作树,它将在末尾附加单词“-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.
. Caveat: untracked files are not considered "dirty", because, as the manpage states, it only cares about the working tree.
. 警告:未跟踪的文件不被视为“脏”,因为正如联机帮助页所述,它只关心工作树。