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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3878624/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 09:14:31  来源:igfitidea点击:

How do I programmatically determine if there are uncommitted changes?

git

提问by Daniel Stutzbach

In a Makefile, I'd like to perform certain actions if there are uncommitted changes (either in the working tree or the index). What's the cleanest and most efficient way to do that? A command that exits with a return value of zero in one case and non-zero in the other would suit my purposes.

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

I can run git statusand pipe the output through grep, but I feel like there must be a better way.

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

回答by VonC

UPDATE: the OP Daniel Stutzbachpoints out in the commentsthat this simple command git diff-indexworked for him:

UPDATE:在OP丹尼尔Stutzbach指出,在评论这个简单的命令git diff-index为他工作:

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

(nornagonmentions in the commentsthat, if there are files that have been touched, but whose contents are the same as in the index, you'll need to run git update-index --refreshbefore git diff-index, otherwise diff-indexwill incorrectly report that the tree is dirty)

nornagon提到的意见,如果有已经触及文件,但其内容是一样的指数,你需要运行git update-index --refresh之前git diff-index,否则diff-index会错误地报告树是脏)

You can then see "How to check if a command succeeded?" if you are using it in a bash script:

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

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

Note: as commentedby Anthony Sottile

注:如评论安东尼Sottile

git diff-index HEAD ...will fail on a branch which has no commits (such as a newly initialized repository).
One workaround I've found is git diff-index $(git write-tree) ...

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

And haridsvpoints out in the commentsthat git diff-fileson a newfile doesn't detect it as a diff.
The safer approach seems to be to run git addon the file spec first and then use git diff-indexto see if anything got added to index before running git commit.

haridsv指出在评论git diff-files上一个新的文件,不检测它作为一个差异。
更安全的方法似乎是git add首先在文件规范上运行,然后git diff-index在运行之前查看是否有任何内容添加到索引中git commit

git add ${file_args} && \
git diff-index --cached --quiet HEAD || git commit -m '${commit_msg}'
git add ${file_args} && \
git diff-index --cached --quiet HEAD || git commit -m '${commit_msg}'

And 6502reports in the comments:

以及评论中的6502报告:

One problem I bumped in is that git diff-indexwill tell that there are differences when indeed there is none except for timestamps of the files.
Running git diffonce solves the issue (surprisingly enough, git diffdoes actually change the content of the sandbox, meaning here .git/index)

我遇到的一个问题是,git diff-index当确实除了文件的时间戳之外没有任何差异时,它会表明存在差异。
运行git diff一次解决了这个问题(令人惊讶的是,git diff确实改变了沙箱的内容,意思是这里.git/index

These timestamp issues can also occur if git is running in docker.

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



Original answer:

原答案:

"Programmatically" means never ever rely on porcelain commands.
Always rely on plumbing commands.

“以编程方式”意味着永远不要依赖瓷器命令
始终依赖管道命令

See also "Checking for a dirty index or untracked files with Git" for alternatives (like git status --porcelain)

另请参阅“使用 Git 检查脏索引或未跟踪文件”以获取替代方案(例如git status --porcelain

You can take inspiration from the new "require_clean_work_treefunction" which is written as we speak;) (early October 2010)

您可以从我们说话时编写的新“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 : 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 : 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
}

回答by Nepthar

While the other solutions are very thorough, if you want something really quick and dirty, try something like this:

虽然其他解决方案非常彻底,但如果您想要真正快速和肮脏的东西,请尝试以下方法:

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

It just checks if there is any output in the status summary.

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

回答by Josh Lee

git diff --exit-codewill return nonzero if there are any changes; git diff --quietis the same with no output. Since you want to check for the working tree and the index, use

git diff --exit-code如果有任何更改,将返回非零值;git diff --quiet没有输出也是一样。由于您要检查工作树和索引,请使用

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

Or

或者

git diff --quiet HEAD

Either one will tell you if there are uncommitted changes that are staged or not.

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

回答by Travis Reeder

Expanding on @Nepthar's answer:

扩展@Nepthar的回答:

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

回答by sanmai

As pointed in other answer, as simple as such command is sufficient:

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

git diff-index --quiet HEAD --

If you omit the last two dashes, the command would fail if you have a file named HEAD.

如果省略最后两个破折号,如果您有一个名为HEAD.

Example:

例子:

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

# continue as planned...

Word of caution: this command ignores untracked files.

注意事项:此命令会忽略未跟踪的文件。

回答by stk

I created some handy git aliases to list unstaged and staged files:

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

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

Then you can easily do things like:

然后,您可以轻松执行以下操作:

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


You can make it more readable by creating a script somewhere on your PATHcalled git-has:

您可以通过在PATH被调用的某处创建一个脚本来使其更具可读性git-has

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

Now the above examples can be simplified to:

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

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


For completeness here are similar aliases for untracked and ignored files:

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

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

回答by Pablo

With python and the GitPython package:

使用 python 和 GitPython 包:

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

Returns True if repository is not clean

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

回答by codyc4321

Here is the best, cleanest way.

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

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
}