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
How do I programmatically determine if there are uncommitted changes?
提问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 status
and 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-index
worked 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 --refresh
before git diff-index
, otherwise diff-index
will 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 isgit diff-index $(git write-tree) ...
git diff-index HEAD ...
将在没有提交的分支上失败(例如新初始化的存储库)。
我发现的一种解决方法是git diff-index $(git write-tree) ...
And haridsv
points out in the commentsthat git diff-files
on a newfile doesn't detect it as a diff.
The safer approach seems to be to run git add
on the file spec first and then use git diff-index
to 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-index
will tell that there are differences when indeed there is none except for timestamps of the files.
Runninggit diff
once solves the issue (surprisingly enough,git diff
does 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_tree
function" 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-code
will return nonzero if there are any changes; git diff --quiet
is 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 PATH
called 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
}