在Makefile中,如果存在未提交的更改(在工作树或索引中),我想执行某些操作。什么是最干净,最有效的方法?退出的命令在一种情况下返回值为零而在另一种情况下为非零符合我的目的。
我可以运行git status
并通过grep
管道输出,但我觉得必须有更好的方法。
答案 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
git diff-index HEAD ...
将在没有提交的分支上失败(例如新初始化的存储库) 我找到的一个解决方法是git diff-index $(git write-tree) ...
“以编程方式”表示永远不会依赖porcelain commands 始终信赖plumbing commands 。
有关替代方案(例如git status --porcelain
)
你可以获得灵感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
}