如何以编程方式确定是否存在未提交的更改?

时间:2010-10-07 04:16:14

标签: git

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

我可以运行git status并通过grep管道输出,但我觉得必须有更好的方法。

10 个答案:

答案 0 :(得分:240)

更新:OP Daniel Stutzbach指出这个简单命令in the comments为他工作的git diff-index

git diff-index --quiet HEAD --

如果您在bash脚本中使用它,则可以看到“How to check if a command succeeded?”:

git diff-index --quiet HEAD -- || echo "untracked"; // do something about it

注意:commentedAnthony Sottile

  

git diff-index HEAD ...将在没有提交的分支上失败(例如新初始化的存储库)   我找到的一个解决方法是git diff-index $(git write-tree) ...


“以编程方式”表示永远不会依赖porcelain commands 始终信赖plumbing commands

有关替代方案(例如git status --porcelain

,另请参阅“Checking for a dirty index or untracked files with Git

你可以获得灵感from the new "require_clean_work_tree function" which is written as we speak;)(2010年10月初)

require_clean_work_tree () {
    # Update the index
    git update-index -q --ignore-submodules --refresh
    err=0

    # Disallow unstaged changes in the working tree
    if ! git diff-files --quiet --ignore-submodules --
    then
        echo >&2 "cannot $1: you have unstaged changes."
        git diff-files --name-status -r --ignore-submodules -- >&2
        err=1
    fi

    # Disallow uncommitted changes in the index
    if ! git diff-index --cached --quiet HEAD --ignore-submodules --
    then
        echo >&2 "cannot $1: your index contains uncommitted changes."
        git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
        err=1
    fi

    if [ $err = 1 ]
    then
        echo >&2 "Please commit or stash them."
        exit 1
    fi
}

答案 1 :(得分:82)

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

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

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

答案 2 :(得分:51)

如果有任何更改,

git diff --exit-code将返回非零值; git diff --quiet是相同的,没有输出。由于您要检查工作树和索引,请使用

git diff --quiet && git diff --cached --quiet

或者

git diff --quiet HEAD

任何一个都会告诉您是否存在未提交的未提交的更改。

答案 3 :(得分:13)

扩大@Nepthar的答案:

if [[ -z $(git status -s) ]]
then
  echo "tree is clean"
else
  echo "tree is dirty, please commit changes before running this"
  exit
fi

答案 4 :(得分:4)

正如其他答案所指出的那样,这样的命令就足够简单了:

git diff-index --quiet HEAD --

如果省略最后两个破折号,如果您有一个名为HEAD的文件,该命令将失败。

示例:

#!/bin/bash
set -e
echo -n "Checking if there are uncommited changes... "
trap 'echo -e "\033[0;31mFAILED\033[0m"' ERR
git diff-index --quiet HEAD --
trap - ERR
echo -e "\033[0;32mAll set!\033[0m"

# continue as planned...

提醒:此命令忽略未跟踪的文件。

答案 5 :(得分:3)

一些答案​​既使问题复杂化,又没有达到预期的结果。例如。接受的答案会丢失未跟踪的文件。

尽管某些人(错误地)在注释中说了另外的话,但使用提供的git status --porcelain,它是设计为机器可解析的。如果git status中出现了某些内容,那就是我认为工作目录很脏的时候。因此,我使用测试[ -z "$(git status --porcelain=v1 2>/dev/null)" ]进行了清洁度测试,如果在git目录之外运行,该测试也会通过。

最小工作示例:

[ -z "$(git status --porcelain=v1 2>/dev/null)" ] && echo "git undirty"

git status(到目前为止)中显示的所有内容都会正确触发此测试。 =v1位可确保git版本之间的输出格式一致。


额外:计数脏文件

this answer的启发。您grep输出git status --porcelain=v1的行。每行的前两个字符指示特定文件的状态。重复grep后,您可以通过将输出传递到wc -l来统计有多少状态,该行会计算行数。

例如如果该脚本在git存储库中运行,它将打印一些信息。

#!/bin/sh
GS=$(git status --porcelain=v1 2>/dev/null) # Exit code 128 if not in git directory. Unfortunately this exit code is a bit generic but it should work for most purposes.
if [ $? -ne 128 ]; then
  function _count_git_pattern() {
    echo "$(grep "^$1" <<< $GS | wc -l)" 
  }                                           
  echo "There are $(_count_git_pattern "??") untracked files."                                 
  echo "There are $(_count_git_pattern " M") unstaged, modified files."
  echo "There are $(_count_git_pattern "M ")   staged, modified files."        
fi

答案 6 :(得分:2)

我创建了一些方便的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'

答案 7 :(得分:1)

工作树是“干净的”如果

git ls-files --deleted --modified --others --exclude-standard

什么都不返回。

说明

  • --deleted 检查工作树中删除的文件
  • --modified 检查工作树中修改的文件
  • --others 检查添加到工作树中的文件
  • --exclude-standard 根据通常的 .gitignore, .git/info/exclude ... 规则忽略

如果工作树是干净的,则输出为空

答案 8 :(得分:0)

使用Python和GitPython:

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

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

答案 9 :(得分:-3)

这是最好,最干净的方式。

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
}