使用Git检查脏索引或未跟踪的文件
我如何检查我的git仓库中是否有任何未提交的更改:
- 添加到索引但未提交的更改
- 未追踪的文件
从脚本?
git-status
似乎总是用git版本1.6.4.2返回零。
好时机! 我几天前写了一篇关于这个的博客文章,当时我想到了如何将Git状态信息添加到我的提示中。
这就是我所做的:
-
对于脏的状态:
# Returns "*" if the current git branch is dirty. function evil_git_dirty { [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*" }
-
对于未跟踪的文件(注意 – –
--porcelain
标志git status
,这给你很好的可parsing的输出):# Returns the number of untracked files function evil_git_num_untracked_files { expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l` }
虽然git diff --shortstat
更方便,但您也可以使用git status --porcelain
来获取脏文件:
# Get number of files added to the index (but uncommitted) expr $(git status --porcelain 2>/dev/null| grep "^M" | wc -l) # Get number of files that are uncommitted and not added expr $(git status --porcelain 2>/dev/null| grep "^ M" | wc -l) # Get number of total uncommited files expr $(git status --porcelain 2>/dev/null| egrep "^(M| M)" | wc -l)
注意: 2>/dev/null
过滤掉错误信息,所以你可以在非git目录中使用这些命令。 (他们只会返回0
的文件数量。)
编辑 :
这里是post:
将Git状态信息添加到您的terminal提示符
改进了启用Git的Shell提示符
可靠地“脚本化”Git的关键是使用“pipe道”命令。
开发人员在更改pipe道命令时要小心,以确保它们提供非常稳定的接口(即,存储库状态,stdin,命令行选项,参数等的给定组合将在所有Git版本中产生相同的输出,其中命令/选项存在)。 pipe道命令中新的输出variables可以通过新的选项来引入,但是对于已经针对旧版本编写的程序不会引入任何问题(他们不会使用新的选项,因为它们不存在(或者至less是不用)写脚本时)。
不幸的是,“日常”的Git命令是“瓷器”命令,所以大多数Git用户可能不熟悉pipe道命令。 瓷器和pipe道命令之间的区别是在主要的git手册页中进行的 (参见标题为“ 高级命令(瓷器)”和“ 低级命令(pipe道)”的小节) 。
要找出未改变的变化,你可能需要git diff-index
(比较索引(可能跟踪工作树的位)和其他树状的(比如HEAD
)),可能是git diff-files
(比较工作树和索引)并可能git ls-files
(列表文件;例如列表未追踪,不受限制的文件)。
(请注意,在下面的命令中,使用HEAD --
而不是HEAD
因为如果有一个名为HEAD
的文件,命令将会失败 。
要检查一个存储库是否已经进行了更改(尚未提交),请使用以下命令:
git diff-index --quiet --cached HEAD --
- 如果它以
0
退出,则没有区别(1
表示有差异)。
要检查一个工作树是否有变化,可以上演:
git diff-files --quiet
- 退出代码与
git diff-index
(0
==没有区别;1
==区别)。
检查工作树中索引和跟踪文件的组合是否相对于HEAD
有变化:
git diff-index --quiet HEAD --
- 这就像前两者的组合。 一个主要区别是,如果您在工作树中已经“取消”了一个分阶段更改(回到
HEAD
的内容),它仍然会报告“没有区别”。 在这种情况下,两个单独的命令都会返回“存在差异”的报告。
你还提到了未跟踪的文件。 你可能意思是“没有跟踪和无主的”,或者你可能只是简单的“未跟踪”(包括被忽略的文件)。 无论哪种方式, git ls-files
是工作的工具:
对于“未跟踪”(将包括忽略的文件,如果存在):
git ls-files --others
对于“未受打击和无法无天”:
git ls-files --exclude-standard --others
我的第一个想法是只检查这些命令是否有输出:
test -z "$(git ls-files --others)"
- 如果它退出
0
那么没有未跟踪的文件。 如果它退出1
然后有未跟踪的文件。
有一个很小的机会,这将会把git ls-files
exception退出转换成“no untracked files”报告(都会导致上述命令的非零退出)。 一个更健壮的版本可能看起来像这样:
u="$(git ls-files --others)" && test -z "$u"
- 这个想法和前面的命令是一样的,但是它允许从
git ls-files
传出的意外错误。 在这种情况下,非零出口可能意味着“有未跟踪的文件”,或者可能意味着发生了错误。 如果你想把“error”结果与“no untracked files”结合起来,可以使用test -n "$u"
(其中0
表示“未跟踪的文件”,而非零表示错误或者“没有未跟踪的文件“)。
另一个想法是使用--error-unmatch
在没有未跟踪文件的情况下导致非零的退出。 这也冒着将“没有未跟踪的文件”(出口1
)与“发生错误”(退出非零,但可能是128
)混为一谈的风险。 但检查0
与1
与非零退出代码可能相当强大:
git ls-files --others --error-unmatch . >/dev/null 2>&1; ec=$? if test "$ec" = 0; then echo some untracked files elif test "$ec" = 1; then echo no untracked files else echo error from ls-files fi
上面的任何一个git ls-files
例子都可以采用--exclude-standard
如果你只想考虑未被跟踪和未被忽略的文件。
假设你在git 1.7.0或更高版本…
阅读本页所有答案和一些实验后,我认为正确性和简洁性恰当组合的方法是:
test -n "$(git status --porcelain)"
虽然git允许跟踪,忽略,未跟踪但不受限制等等之间的细微差别,我相信典型的用例是自动化构build脚本,如果您的结帐不干净,您想停止一切。
在这种情况下,模拟程序员会做什么是有意义的:inputgit status
并查看输出。 但是我们不想依赖具体的词语,所以我们使用1.7.0中引入的 – --porcelain
模式; 启用时,干净的目录不会导致输出。
然后我们使用test -n
来查看是否有输出。
如果工作目录是干净的,则该命令将返回1,如果有更改要提交,则该命令返回0。 如果你想要相反的话,你可以把-n
改成-z
。 这对于链接脚本中的命令非常有用。 例如:
test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"
这有效地说:“要么没有改变,要么发出警报”; 这个单线可能比if语句更可取,这取决于您正在编写的脚本。
来自VonC的答案的一个实现:
if [[ -n $(git status --porcelain) ]]; then echo "repo is dirty"; fi
看看这些答案中的一些…(并且在* nix和windows上有各种问题,这是我的要求)…发现以下运作良好…
git diff --no-ext-diff --quiet --exit-code
检查* nix中的退出码
echo $? #returns 1 if the repo has changes (0 if clean)
检查窗口$中的退出代码
echo %errorlevel% #returns 1 if the repos has changes (0 if clean)
来自https://github.com/sindresorhus/pure/issues/115感谢@paulirish这篇文章的分享;
为什么不用一个脚本封装' git status
:
- 将分析该命令的输出
- 将根据您的需要返回相应的错误代码
这样,您可以在脚本中使用“增强”状态。
正如0xfe在他的优秀答案中提到的那样, git status --porcelain
在任何基于脚本的解决scheme中都是有用的
--porcelain
为脚本提供稳定的,易于parsing的格式输出。
目前这与--short output
相同,但是保证将来不会改变,使得脚本安全。
一个DIY的可能性,更新为遵循0xfe的build议
#!/bin/sh exit $(git status --porcelain | wc -l)
正如Chris Johnsen所指出的,这只适用于Git 1.7.0或更新的版本。
这是一个更容易shell的变种,用于查找存储库中是否存在未跟踪的文件:
# Works in bash and zsh if [[ "$(git status --porcelain 2>/dev/null)" = *\?\?* ]]; then echo untracked files fi
这不会分叉第二个进程, grep
,并且不需要检查是否在git存储库中。 这对于shell提示很方便
有可能是从这个线程的答案更好的组合..但这对我的作品…为您的.gitconfig
的[alias]
节…
# git untracked && echo "There are untracked files!" untracked = ! git status --porcelain 2>/dev/null | grep -q "^??" # git unclean && echo "There are uncommited changes!" unclean = ! ! git diff --quiet --ignore-submodules HEAD > /dev/null 2>&1 # git dirty && echo "There are uncommitted changes OR untracked files!" dirty = ! git untracked || git unclean
我用来检测脏状态的最简单的自动testing= 任何更改,包括未跟踪的文件 :
git add --all git diff-index --exit-code HEAD
注意:
- 没有
add --all
diff-index
不会注意到未跟踪的文件。 - 通常情况下,我testing错误代码后,运行
git reset
将所有东西都取消。
你也可以做
git describe --dirty
。 如果它检测到一个脏的工作树,它将在末尾附加单词“-dirty”。 根据git-describe(1)
:
--dirty[=<mark>] Describe the working tree. It means describe HEAD and appends <mark> (-dirty by default) if the working tree is dirty.
。 警告:未跟踪的文件不被认为是“脏的”,因为正如手册页所述,它只关心工作树。
这是最好的,最干净的方法。 由于某些原因,所选的答案对我来说不起作用,它没有select那些没有提交的新文件。
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 }