使用Git检查脏索引或未跟踪的文件

我如何检查我的git仓库中是否有任何未提交的更改:

  1. 添加到索引但未提交的更改
  2. 未追踪的文件

从脚本?

git-status似乎总是用git版本1.6.4.2返回零。

好时机! 我几天前写了一篇关于这个的博客文章,当时我想到了如何将Git状态信息添加到我的提示中。

这就是我所做的:

  1. 对于脏的状态:

     # Returns "*" if the current git branch is dirty. function evil_git_dirty { [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*" } 
  2. 对于未跟踪的文件(注意 – – --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-index0 ==没有区别; 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-filesexception退出转换成“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 )混为一谈的风险。 但检查01与非零退出代码可能相当强大:

 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存储库中。 这对于s​​hell提示很方便

有可能是从这个线程的答案更好的组合..但这对我的作品…为您的.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 }