在Makefile中,如果有未提交的更改(在工作树或索引中),我希望执行某些操作。最干净、最有效的方法是什么?在一种情况下退出时返回值为零,而在另一种情况下返回值为非零的命令适合我的目的。

我可以运行git状态并通过grep管道输出,但我觉得一定有更好的方法。


当前回答

虽然其他的解决方案非常彻底,但如果你想要一些非常快速和肮脏的东西,可以试试这样的方法:

[[ -z $(git status -s) ]]

它只是检查状态摘要中是否有任何输出。

其他回答

这是最好、最干净的方法。

function git_dirty {
    text=$(git status)
    changed_text="Changes to be committed"
    untracked_files="Untracked files"

    dirty=false

    if [[ ${text} = *"$changed_text"* ]];then
        dirty=true
    fi

    if [[ ${text} = *"$untracked_files"* ]];then
        dirty=true
    fi

    echo $dirty
}

虽然其他的解决方案非常彻底,但如果你想要一些非常快速和肮脏的东西,可以试试这样的方法:

[[ -z $(git status -s) ]]

它只是检查状态摘要中是否有任何输出。

使用python和GitPython包:

import git
git.Repo(path).is_dirty(untracked_files=True)

如果存储库不干净,则返回True

在Linux Ubuntu的bash终端上测试。

Shell脚本以编程方式解释git状态的输出

...并告诉你:

它有一个错误 它显示您的工作树是干净的(没有未提交的更改),或者 它显示您的工作树是脏的(您有未提交的更改)。

这里有一个很好的答案:Unix和Llinux:从脚本中确定Git工作目录是否干净。我的回答就是基于此。

我们将在git状态下使用——porcelain选项,因为它是由脚本解析的!

从man git状态(强调添加):

——瓷(= <版本>) 为脚本提供易于解析的输出格式。这类似于短的输出,但是无论用户配置如何,在Git版本之间都保持稳定。详情见下文。 version参数用于指定格式版本。这是可选的,默认为原始版本v1格式。

所以,这样做:

选项1

if output="$(git status --porcelain)" && [ -z "$output" ]; then
    echo "'git status --porcelain' had no errors AND the working directory" \
         "is clean."
else 
    echo "Working directory has UNCOMMITTED CHANGES."
fi

第一部分,如果output=$(git status——porcelain)将失败,如果git status——porcelain命令有错误,则跳转到else子句。第二部分&& [-z "$output"]测试输出变量是否包含空字符串(长度为零)。如果是,那么git状态是干净的,没有任何变化。

选项2

然而,通常我更喜欢的用法是用-n(非零)而不是-z(零)来否定测试,并像这样做:

if output="$(git status --porcelain)" && [ -n "$output" ]; then
    echo "'git status --porcelain' had no errors AND the working directory" \
         "is dirty (has UNCOMMITTED changes)."
    # Commit the changes here
    git add -A
    git commit -m "AUTOMATICALLY COMMITTING UNCOMMITTED CHANGES"
fi

选项3

一种更细粒度的方式来编写上面的第一个代码块是这样的:

if ! git_status_output="$(git status --porcelain)"; then
    # `git status` had an error
    error_code="$?"
    echo "'git status' had an error: $error_code" 
    # exit 1  # (optional)
elif [ -z "$git_status_output" ]; then
    # Working directory is clean
    echo "Working directory is clean."
else
    # Working directory has uncommitted changes.
    echo "Working directory has UNCOMMITTED CHANGES."
    # exit 2  # (optional)
fi

我已经测试了上面所有的代码,在不同的状态下复制和粘贴整个块到我的终端,它在所有3种情况下都能正常工作:

您的git status命令错误或拼写错误 Git状态是干净的(没有未提交的更改) Git状态是脏的(你有未提交的更改)

要强制'git status'有一个错误输出,只需将——porcelain选项拼写为——porcelain或其他东西,你会在最后看到这个输出:

'git status'有一个错误:0

我创建了一些方便的git别名来列出非暂存和暂存文件:

git config --global alias.unstaged 'diff --name-only'
git config --global alias.staged 'diff --name-only --cached'

然后你可以轻松地做以下事情:

[[ -n "$(git unstaged)" ]] && echo unstaged files || echo NO unstaged files
[[ -n "$(git staged)" ]] && echo staged files || echo NO staged files

你可以通过在PATH的某个地方创建一个名为git-has的脚本来让它更具可读性:

#!/bin/bash
[[ $(git "$@" | wc -c) -ne 0 ]]

现在上面的例子可以简化为:

git has unstaged && echo unstaged files || echo NO unstaged files
git has staged && echo staged files || echo NO staged files

为了完整起见,这里为未跟踪和忽略的文件提供了类似的别名:

git config --global alias.untracked 'ls-files --exclude-standard --others'
git config --global alias.ignored 'ls-files --exclude-standard --others --ignored'