在Makefile中,如果有未提交的更改(在工作树或索引中),我希望执行某些操作。最干净、最有效的方法是什么?在一种情况下退出时返回值为零,而在另一种情况下返回值为非零的命令适合我的目的。
我可以运行git状态并通过grep管道输出,但我觉得一定有更好的方法。
在Makefile中,如果有未提交的更改(在工作树或索引中),我希望执行某些操作。最干净、最有效的方法是什么?在一种情况下退出时返回值为零,而在另一种情况下返回值为非零的命令适合我的目的。
我可以运行git状态并通过grep管道输出,但我觉得一定有更好的方法。
当前回答
有些答案会使问题过于复杂,或者没有达到预期的结果。例如,接受的答案错过了未跟踪的文件。
您可以使用git status——porcelain=v1并以编程方式解析输出。如果有一些未提交的更改,则输出为空,否则输出不为空。
一个posix兼容的最小工作示例:
[ -z "$(git status --porcelain=v1 2>/dev/null)" ] && echo "No uncommitted changes."
如果在git存储库外部运行,仍然会显示No uncommitted changes。
细节
The option --porcelain gives a machine-parseable output. The option specification --porcelain=v1 fixes the output version of the machine-parseable output, so that your script will never break under a future git update. As of my writing, you can check https://git-scm.com/docs/git-status for information about other version options, like --porcelain=v2. You may be able to do more advanced scripting with versions beyond v1. The 2>/dev/null is there so that git status will fail silently, if at all (i.e., if run outside of a git repository). As of this writing, the command git status ... will return exit code 128 if it is not inside a git repository. You can check explicitly for this exit code if you want a third option besides "uncommitted changes" or "no uncommitted changes".
额外:统计脏文件
受到这个答案的启发。你grep的git状态行瓷器=v1输出。每行的前两个字符表示特定文件的状态。在grepping之后,通过将输出输出输送到wc -l来计算有多少行处于这种状态,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
其他回答
虽然其他的解决方案非常彻底,但如果你想要一些非常快速和肮脏的东西,可以试试这样的方法:
[[ -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
}
更新: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
}
使用python和GitPython包:
import git
git.Repo(path).is_dirty(untracked_files=True)
如果存储库不干净,则返回True
Git diff——exit-code如果有任何变化将返回非零;Git diff——quiet是相同的,没有输出。由于您希望检查工作树和索引,请使用
git diff --quiet && git diff --cached --quiet
Or
git diff --quiet HEAD
其中任何一个都将告诉您是否存在暂存的未提交更改。