rsync
。我希望脚本具有不同的行为,具体取决于工作目录是否干净(没有要提交的更改)。例如,如果git status
的输出如下,我希望脚本退出:git status
Already up-to-date.
# On branch master
nothing to commit (working directory clean)
Everything up-to-date
如果目录不干净,那么我希望它执行一些更多命令。
如何在shell脚本中检查上述输出?
#1 楼
解析git status
的输出是一个坏主意,因为该输出旨在供人类读取,而不是机器可读。无法保证在将来的Git版本或不同配置的环境中输出将保持不变。是未提交的更改。但是,它确实提供了git status
选项,该选项可使--porcelain
的输出以易于解析的脚本格式进行格式化,并且在Git版本和任何用户配置下都将保持稳定。我们可以使用
git status --porcelain
的空输出来指示没有更改要提交:if [ -z "$(git status --porcelain)" ]; then
# Working directory clean
else
# Uncommitted changes
fi
如果我们不关心工作目录中未跟踪的文件,我们可以使用
git status --porcelain
选项来忽略那些:到:if [ -z "$(git status --untracked-files=no --porcelain)" ]; then
# Working directory clean excluding untracked files
else
# Uncommitted changes in tracked files
fi
还值得注意的是,尽管当工作目录不整洁时
--untracked-files=no
并没有给出有意义的退出代码,但是git status
提供了stdout
选项,这使其工作与diff实用程序类似,即当存在差异和q4312时以状态git status
退出079q找不到时。使用此方法,我们可以使用以下方法检查未进行的更改: :
if output=$(git status --porcelain) && [ -z "$output" ]; then
# Working directory clean
else
# Uncommitted changes
fi
尽管
git diff
可以通过--exit-code
的适当参数报告子模块中未跟踪的文件,但不幸的是,似乎没有办法报告实际工作目录。如果工作目录中的未跟踪文件相关,则1
可能是最好的选择。评论
ughhh git status --porcelain将以代码0退出,即使未针对提交和未跟踪的文件进行更改。
–亚历山大·米尔斯(Alexander Mills)
18年8月31日在21:19
我有兴趣提前确定git stash是否会做任何事情(它不会输出有用的返回码)。我必须添加--ignore-submodules,否则git status将指示git stash忽略的子模块更改。
–德文·莱恩(Devin Lane)
18-10-27在21:03
@AlexanderMills:我观察到了同样的情况。但是然后检查[-z在做什么。 -z表示如果以下字符串为空,则if的值为true。换句话说,如果此git status --porcelain不产生任何字符串,则该存储库是干净的。如果不是,它将列出已修改/添加/删除的文件,并且不再是空字符串。如果为if,则结果为false。
– Adeynack
19年5月17日在12:36
如果您只想要退出代码,请使用git diff --quiet --exit-code
– kigawas
20年7月2日,3:09
#2 楼
使用:git diff-index --quiet HEAD
返回代码反映了工作目录的状态(0 =干净,1 =脏)。未跟踪的文件将被忽略。
评论
当前目录中有未跟踪的文件时,返回0。
–亚当·帕金(Adam Parkin)
18年4月12日在1:48
如果文件已被触摸/覆盖,但在其他方面与索引相同,则需要先在git diff-index HEAD之前运行git update-index --refresh。更多信息:stackoverflow.com/q/34807971/1407170
–sffc
18年11月1日在2:28
@AdamParkin我只是用git add添加所有文件。在发行之前。通常是在脚本中使用它的方式
–ceztko
18/12/7在13:27
这很棒。请注意,非零的返回/退出代码也将被解释为“错误”,如果您在带有set -e的脚本中,则脚本将在“脏”的情况下退出。可以通过在调用git之前设置set + e并在评估$?之后再次添加set -e来避免这种情况。
– Orion elenzil
19年3月29日在16:00
#3 楼
我做了这种测试TEST=$(git status --porcelain|wc -l)
if [ 0 -eq $TEST ]; then
echo "No changes"
else
echo "Changes"
fi
评论
不必为了确定是否产生了任何行而对行数进行计数,因此,传递给另一个程序很浪费,并且不能很好地表达意图。请参阅Thomas Nyman的答案以获得更好的解决方案。
– ErikE
20年7月13日在4:11
#4 楼
对André的出色回答进行了小扩展。未跟踪的文件将被忽略。
if git diff-index --quiet HEAD
then
GIT_MODS="clean"
else
GIT_MODS="dirty"
fi
评论
访问$?不如直接在命令上使用if:if! git diff-index-安静的HEAD;然后。但是,此方法不是100%可靠的,如果您不先运行git update-index --really-refresh,则可能会出现假阳性的“脏”结果。要查看此操作,请触摸现有的提交文件以仅更新其日期,然后即使实际上没有任何更改,您也会从diff-index中看到非零返回码。
– ErikE
20 Jul 13'4:19
#5 楼
如何使用git describe --broken --dirty --all
并检查结果以查看是否以-dirty
(或-broken
)结尾;然后,在具有git submodule foreach ...
的所有子模块上使用相同的东西吗?据我所知,这需要现代的(版本> = 3.x)
bash
,它也不会调查未跟踪的文件-我认为这是不合理的(至少如果检出了差异分支,则不应破坏它们!)-请注意,如果一切都干净,它只会返回零退出状态:#!/bin/bash
RESULT=$(git describe --broken --dirty --all)
STATUS="clean"
if [[ "${RESULT}" =~ broken$ ]]; then
# Bail out now, in case it is not safe to look for sub-modules
echo "Main repository is broken."
exit -3
elif [[ "${RESULT}" =~ dirty$ ]]; then
echo "Main repository is dirty - not checking any submodules."
STATUS="dirty"
exit -1
else
git submodule foreach --recursive --quiet 'RESULT=$(git describe --broken --dirty --all)
if [[ "${RESULT}" =~ broken$ ]]; then
echo "Submodule ${name} is broken."
exit -3
elif [[ "${RESULT}" =~ dirty$ ]]; then
echo "Submodule ${name} is dirty."
STATUS="dirty"
else
echo "Submodule ${name} is clean."
fi'
echo -n "Main repository is clean "
if [ "${STATUS}" = "dirty" ]; then
echo "- but at least one submodule is dirty."
exit -2
else
echo "- and so are any submodules."
fi
fi
exit 0
评论
在这里检查上一条命令的状态会有所帮助吗? ($?)您能提供更多细节吗?您的脚本的主要思想是什么?
@tachomi我在编辑中添加了上下文
您可以假设它不干净,然后进行git reset --hard origin / branch(如果您要这样做的话)...就像您在编译某些内容后尝试进行清理等。
@SnakeDoc您可以,但是我认为反情况会更常见,即如果工作目录很脏,请退出以免处理本地更改。考虑这两种情况将使问题对将来的读者更有用。