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

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


当前回答

工作树是“干净的”,如果

git ls-files \
  --deleted \
  --modified \
  --others \
  --exclude-standard \
  -- :/

返回什么。

解释

——deleted检查工作树中已删除的文件 ——modified检查工作树中修改的文件 ——其他检查文件添加到工作树 ——根据通常的.gitignore, .git/info/exclude…规则 ——:/ pathspec的一切,如果不是运行在存储库的根

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

其他回答

Git diff——exit-code如果有任何变化将返回非零;Git diff——quiet是相同的,没有输出。由于您希望检查工作树和索引,请使用

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

Or

git diff --quiet HEAD

其中任何一个都将告诉您是否存在暂存的未提交更改。

扩展@Nepthar的回答:

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

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

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
}

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

更新:OP Daniel Stutzbach在评论中指出,这个简单的命令git diff-index对他有用:

git update-index --refresh 
git diff-index --quiet HEAD --

一个更精确的选项是测试git状态——porcelain=v1 2>/dev/null | wc -l,使用瓷选项。 请看米里亚姆的回答。

(nornagon在评论中提到,如果有文件被触碰过,但其内容与索引中的内容相同,你需要在git diff-index之前运行git update-index——refresh,否则diff-index将错误地报告树是脏的)

如果你在bash脚本中使用它,你可以看到“如何检查命令是否成功?”

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

注:正如Anthony Sottile所评论的

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

haridsv在评论中指出,git在新文件上的diff-files不会将其检测为diff。 更安全的方法似乎是先在文件规范上运行git add,然后在运行git commit之前使用git diffi -index查看是否有任何东西被添加到索引中。

git添加${file_args} &\

git diff-index --cached --quiet HEAD || git commit -m '${commit_msg}'

6502在评论中报告:

我碰到的一个问题是,git diff-index会告诉你,除了文件的时间戳之外,实际上没有任何差异。 运行git diff一次就能解决这个问题(令人惊讶的是,git diff实际上改变了沙盒的内容,也就是这里的.git/index)

如果git在docker中运行,这些时间戳问题也会发生。


最初的回答:

“程序化”意味着永远不要依赖瓷一样的命令。 始终依赖管道命令。

参见“用Git检查脏索引或未跟踪的文件”获得替代方案(如Git status—porcelain)

您可以从新的“require_clean_work_tree函数”中获得灵感,它正在编写;)(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
}