如何检查当前分支中没有什么要提交的?


172

目的是获得可以在shell命令中评估的明确状态。

我尝试过,git status但是即使有要提交的项目,它也总是返回0。

git status
echo $?  #this is always 0

我有一个主意,但我认为这是一个坏主意。

if [ git status | grep -i -c "[a-z]"> 2 ];
then
 code for change...
else
  code for nothing change...
fi

还有其他方法吗?


使用以下解决方法进行更新,请参阅Mark Longair的帖子

我试过了,但这会引起问题。

if [ -z $(git status --porcelain) ];
then
    echo "IT IS CLEAN"
else
    echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    echo git status
fi

我收到以下错误 [: ??: binary operator expected

现在,我看着那个男人,尝试git diff。

==================我的希望,希望更好的答案=======================

#if [ `git status | grep -i -c "$"` -lt 3 ];
# change to below code,although the above code is simple, but I think it is not strict logical
if [ `git diff --cached --exit-code HEAD^ > /dev/null && (git ls-files --other --exclude-standard --directory | grep -c -v '/$')` ];
then
        echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    exit 1

else
    exit 0
fi

4
在更新的部分中,您似乎并没有真正按照eckes他的回答中的建议进行操作-正如他所说,您需要在两端加上双引号$(git status --porcelain)。另外,如果你想要把感叹号在你的消息,你需要使用单引号,而不是双引号-也就是说,它应该是echo 'PLEASE COMMIT YOUR CHANGE FIRST!!!'代替
马克Longair

4
正如Mark所说:您需要在上加上双引号$(git status --porcelain),就像我告诉您的一样!
eckes 2011年

1
如果它不包含部分答案,那么这些问题将大有用处。
2012年

@ 9nix00可以告诉您,并编辑和修复上面的Shell脚本中的错误:错误:if [-z $(some command)]修复:if [-z“ $(some command)”]
MarcH

Answers:


230

测试的输出是否git status --porcelain为空的另一种方法是分别测试您关心的每个条件。例如,如果输出中存在未跟踪的文件,则可能并不总是在意git status

例如,要查看是否有任何本地未暂存的更改,可以查看以下代码的返回代码:

git diff --exit-code

要检查是否已暂存但未提交任何更改,可以使用以下返回代码:

git diff --cached --exit-code

最后,如果您想知道工作树中是否有任何未被忽略的未跟踪文件,则可以测试以下命令的输出是否为空:

git ls-files --other --exclude-standard --directory

更新: 您在下面询问是否可以更改该命令以在输出中排除目录。您可以通过添加来排除空目录--no-empty-directory,但要排除该输出中的所有目录,我认为您必须过滤输出,例如:

git ls-files --other --exclude-standard --directory | egrep -v '/$'

-vegrep装置仅输出线不匹配的图案,并且图案的任何线与一个端部相匹配/


我探究了这些技巧,并遇到了问题。也就是说,使用git ls-files --other --exclude-standard --directory获取列表包含目录。是否有某种方式排除这些目录?
9nix00 2011年

是的,这是我想要的。然后更新我的帖子以获取新的脚本代码。我认为您的建议是更严格的逻辑,尽管会有更多的代码大声笑……并希望出现更好的答案。
2011年

3
@albfan:它在git-diff手册页中:“使程序退出时使用类似于diff(1)的代码。也就是说,如果存在差异,则以1退出,而0则表示没有差异。”
Mark Longair 2014年

只是要指出,它至少从2007年开始就存在13da0fc0,对于shell脚本非常方便,并且与git的较早版本完全兼容
albfan 2014年

9
--quiet(这意味着--exit-code)对于只需要退出代码的用户也使输出静音。
ph

112

返回值git status只是告诉您的退出代码git status,而不是是否有任何要提交的修改。

如果您想要更计算机可读的git status输出版本,请尝试

git status --porcelain

有关git status更多信息,请参见的描述。

示例用法(脚本仅测试是否git status --porcelain给出任何输出,无需解析):

if [ -n "$(git status --porcelain)" ]; then
  echo "there are changes";
else
  echo "no changes";
fi

请注意,您必须引用要测试的字符串,即的输出git status --porcelain。有关测试构造的更多提示,请参阅《高级Bash脚本指南》(部分字符串比较)。


嗨,您给出了一个很好的建议,我尝试了一下,但是在脚本中,它引起了一些问题,我改进了它,如果我们使用它的话[-z $(git status --porcelain)]; 它将出现一些错误,[:??:二进制运算符应该可以找到手册,如果[-z $(git status --short)]可以使用它;这可以工作,谢谢!
9nix00 2011年

抱歉,仍然存在问题。当提交是干净的。使用瓷器和短都可以。但是提交不干净时。这会导致错误。[:??:二进制运算符。我认为也许我们应该尝试使用base64对其进行编码。让我尝试!正在下载base64命令工具....大声笑
9nix00

提交不干净时会导致问题。
9nix00 2011年

1
很好的解决方案。为了增强鲁棒性,您可以|| echo no在命令替换后附加内容,这样即使git status从根本上失败,也不会错误地将工作区报告为干净。此外,您的代码(值得称赞的)是POSIX兼容的,但是由于您链接到bash指南,因此我要补充一点,如果您使用bash [[ ... ]]而不是POSIX兼容[ ... ],则无需双引号替换命令(尽管它没有任何伤害)[[ -z $(git status --porcelain) ]]
mklement0 2014年

@eckes我几天前开始了一个新的仓库,我添加了一个提交,我试图写一些预提交挂钩,并检查要提交的内容以及您所说的对我的情况不起作用。
alinsoar

33

如果像我一样,您想知道是否有:

1)更改现有文件2)新添加的文件3)删除的文件

特别是不想了解4)未跟踪的文件。

应该这样做:

git status --untracked-files=no --porcelain

如果回购是干净的,这是我退出脚本的bash代码。它使用未跟踪文件选项的简短版本:

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;

4
为+1 —untracked-files=no;我认为您的测试可以简化为[[ -z $(git status --untracked-files=no --porcelain) ]]git status除非基本错误,否则不应该写到stderr-然后您确实想查看该输出。(如果您希望在该事件中表现出更强健的行为,|| echo no请在命令替换后附加,以使清洁度测试仍然失败)。字符串比较/ -z运算符可以处理多行字符串-不需要tail
mklement0 2014年

2
谢谢@ mklement0,甚至更短:[[ -z $(git status -u no --porcelain) ]]
moodboom 2014年

1
更正:我的较短版本实际上只是检查名为“ no”的文件的状态!zz 应该是: [[ -z $(git status -uno --porcelain) ]]
moodboom 2015年

2
我感谢后续行动;这是一个微妙的错误-课程是, 带有可选参数的简短选项必须直接附加参数,且中间不能有空格。如何将更正后的简短版本直接纳入您的答案中?
mklement0

9

可以将其git status --porcelain与简单grep的测试结合起来。

if git status --porcelain | grep .; then
    echo Repo is dirty
else
    echo Repo is clean
fi

有时我将其用作简单的单线:

# pull from origin if our repo is clean
git status --porcelain | grep . || git pull origin master

添加-qs到您的grep命令以使其静音。


2
+1优雅;轻微警告:如果git status致命失败(例如,回购损坏),您的测试将错误地报告干净的工作空间。一种选择是使用git status --porcelain 2>&1,但是如果将grep与一起使用,那会“吃掉”错误消息-q。(与处理就失去了优雅:(git status --porcelain || echo err) | grep -q .
mklement0

或者,可以写:test -z "$(git status --porcelain)" || git pull origin master
VasiliNovikov '18

5

git源代码中有一个sh脚本,其中包括以下内容。

require_clean_work_tree () {
    git rev-parse --verify HEAD >/dev/null || exit 1
    git update-index -q --ignore-submodules --refresh
    err=0

    if ! git diff-files --quiet --ignore-submodules
    then
        echo >&2 "Cannot $1: You have unstaged changes."
        err=1
    fi

    if ! git diff-index --cached --quiet --ignore-submodules HEAD --
    then
        if [ $err = 0 ]
        then
            echo >&2 "Cannot $1: Your index contains uncommitted changes."
        else
            echo >&2 "Additionally, your index contains uncommitted changes."
        fi
        err=1
    fi

    if [ $err = 1 ]
    then
        test -n "$2" && echo >&2 "$2"
        exit 1
    fi
}

此代码段显示了如何使用它git diff-files以及git diff-index如何查找以前已知的文件是否有任何更改。但是,它不允许您确定是否已将新的未知文件添加到工作树中。


除了新文件以外,这个都可以正常工作。我们可以添加它。如果!git ls文件-其他-排除标准-目录| grep -c -v'/ $'然后退出0否则echo“请提交新文件,如果不想添加,请添加到git-ignore文件中。” 退出1 fi
9nix00 2011年

只是if [ -n "$(git ls-files --others --exclude-standard)" ],没有任何额外的管道或greping应该足以检测未跟踪文件。
Arrowmaster

5

我会对此进行测试:

git diff --quiet --cached

或明确地说:

git diff --quiet --exit-code --cached

哪里:

-退出代码

使用类似于diff(1)的代码使程序退出。也就是说,如果存在差异,则以1退出,而0表示没有差异。

- 安静

禁用程序的所有输出。暗示--exit-code


3

我在讨论中有点晚了,但是如果仅git status --porcelain返回零则返回0,否则返回0,请尝试以下操作:

exit $( git status --porcelain | wc -l )

这将使行数成为退出代码,而当行数超过255时,就有发生问题的风险。所以

exit $( git status --porcelain | head -255 | wc -l )

将占;)


1
如果输出超过255行,则基本上是不确定的。
3:32

很好发现,谢谢!
Skeeve

2

我在脚本中使用它来具有:

  • 一切正常时为0
  • 差异文件或未跟踪文件时为1

    [-z“ $(git status --porcelain)”]


使用起来if ! git diff --quiet; then更干净,性能更高(我认为)。换句话说,请使用退出代码,而不是标准输出。
亚历山大·米尔斯

1
@AlexanderMills的git diff --quiet行为与git status --porcelain缓存更改的行为不同。
马丁·冯·维蒂奇

0

不漂亮,但是可以工作:

git status | grep -qF 'working directory clean' || echo "DIRTY"

不知道该消息是否取决于语言环境,因此请放在LANG=C前面。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.