219

目标是获得可以在 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

10 回答 10

281

测试输出是否为空的另一种方法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 '/$'

-vto表示只输出与模式不匹配的egrep行,并且模式匹配任何以 . 结尾的行/

于 2011-02-28T08:31:14.540 回答
148

的返回值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 脚本指南(部分字符串比较)。

于 2011-02-28T07:43:28.963 回答
41

如果你和我一样,你想知道是否有:

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

并且特别不想知道 4) 未跟踪的文件。

这应该这样做:

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

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

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;
于 2013-02-06T23:42:52.230 回答
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 命令以使其静音。

于 2013-10-10T19:23:43.000 回答
9

我会对此进行测试:

git diff --quiet --cached

或者这是明确的:

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

在哪里:

--退出代码

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

- 安静的

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

于 2016-11-01T14:39:16.587 回答
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-filesgit diff-index找出对先前已知文件是否有任何更改。但是,它不允许您查明是否已将新的未知文件添加到工作树中。

于 2011-03-01T08:11:00.233 回答
4

我在讨论中有点晚了,但如果只是你需要一个退出代码 0 如果git status --porcelain什么都不返回并且 != 0 否则,试试这个:

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

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

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

将说明这一点;)

于 2018-03-28T05:52:26.333 回答
3

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

  • 0 当一切都干净时
  • 1 当有差异或未跟踪的文件时

    [ -z "$(git status --porcelain)" ]

于 2017-12-15T06:40:27.127 回答
0

不漂亮,但有效:

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

不确定消息是否依赖于语言环境,所以可能会LANG=C在前面放一个。

于 2011-02-28T11:44:52.630 回答
0

除了其他解决方案之外,您还可以使用单独的命令(使用git log ranges)——在 fetch 之后——告诉你需要拉取,和/或你需要推送。

如果您需要编写这些脚本:

[ "$(git log ..origin/main)" == "" ] || (
  echo "something new on main"
  .. pull ?
)
[ "$(git rev-list origin/main..)" == "" ] || (
  echo "something new local"
  .. push ?
)

本文中的更多详细信息

于 2021-12-28T12:46:02.463 回答