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

Rob*_*anu 236 git shell

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

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

从脚本?

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

Chr*_*sen 388

可靠地"编写脚本"Git的关键是使用'plumbing'命令.

开发人员在更改管道命令时要小心,以确保它们提供非常稳定的接口(即存储库状态,stdin,命令行选项,参数等的给定组合将在所有版本的Git中产生相同的输出,其中命令/选项存在).管道命令中的新输出变化可以通过新选项引入,但是对于已经针对旧版本编写的程序不会引入任何问题(它们不会使用新选项,因为它们不存在(或者至少是在编写脚本时没用过).

不幸的是,'日常'Git命令是'瓷器'命令,所以大多数Git用户可能不熟悉管道命令.瓷器和管道命令之间的区别在主git联机帮助页中进行(参见标题为高级命令(瓷器)低级命令(管道)的小节.


要了解未经修改的更改,您可能需要git diff-index(比较索引(可能跟踪工作树的位)与其他树木(例如HEAD)),也许git diff-files(比较工作树与索引),以及可能git ls-files(列表文件;例如列表未跟踪) ,未经标记的文件).

(请注意,在下面的命令中,HEAD --使用而不是HEAD因为如果存在名为的文件,命令将失败HEAD.)

要检查存储库是否已暂存更改(尚未提交),请使用以下命令:

git diff-index --quiet --cached HEAD --
Run Code Online (Sandbox Code Playgroud)
  • 如果它0随之退出则没有差异(1意味着存在差异).

要检查工作树是否有可以暂存的更改:

git diff-files --quiet
Run Code Online (Sandbox Code Playgroud)
  • 退出代码与git diff-index(0==无差异; 1==差异)相同.

检查工作树中索引和跟踪文件的组合是否有关于HEAD以下内容的更改:

git diff-index --quiet HEAD --
Run Code Online (Sandbox Code Playgroud)
  • 这就像前两者的组合.一个主要的区别是,如果你有一个你在工作树中"撤消"的阶段性变化(返回到其中的内容HEAD),它仍然会报告"没有差异" .在同样的情况下,两个单独的命令都将返回"存在差异"的报告.

您还提到了未跟踪的文件.你可能的意思是"没有跟踪和不受欢迎",或者你可能意味着只是简单的"未跟踪"(包括被忽略的文件).无论哪种方式,git ls-files是工作的工具:

对于"未跟踪"(将包括被忽略的文件,如果存在):

git ls-files --others
Run Code Online (Sandbox Code Playgroud)

对于"未跟踪和不受欢迎":

git ls-files --exclude-standard --others
Run Code Online (Sandbox Code Playgroud)

我的第一个想法是检查这些命令是否有输出:

test -z "$(git ls-files --others)"
Run Code Online (Sandbox Code Playgroud)
  • 如果它退出0然后没有未跟踪的文件.如果它退出1然后有未跟踪的文件.

这很可能会将异常退出git ls-files转换为"无未跟踪文件"报告(两者都会导致上述命令的非零退出).更健壮的版本可能如下所示:

u="$(git ls-files --others)" && test -z "$u"
Run Code Online (Sandbox Code Playgroud)
  • 这个想法与上一个命令相同,但它允许意外错误git ls-files传播出去.在这种情况下,非零退出可能意味着"有未跟踪的文件"或者它可能意味着发生了错误.如果您希望将"错误"结果与"无跟踪文件"结果相结合,请使用test -n "$u"(其中"退出" 0表示"某些未跟踪文件",非零表示错误或"没有未跟踪文件").

另一个想法是--error-unmatch在没有未跟踪文件时使用导致非零退出.这也存在将"没有未跟踪文件"(退出1)与"发生错误" 混淆的风险(退出非零,但可能128).但检查0vs. 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
Run Code Online (Sandbox Code Playgroud)

如果您只想考虑未跟踪和未签名的文件,则git ls-files可以采用上述任何示例--exclude-standard.

  • @phs:您可能需要在`diff-index`之前执行`git update-index -q --refresh`,以避免因stat(2)信息不匹配而导致的一些"误报". (8认同)
  • 我想指出`git ls-files --others`给出*local*untracked文件,而接受答案的`git status --porcelain`给出了git存储库下的所有未跟踪文件.我不是原始海报中的哪一个想要的,但两者之间的区别很有趣. (5认同)
  • @phunehehe:您需要提供带有“--error-unmatch”的路径规范。尝试(例如)`git ls-files --other --error-unmatch --exclude-standard .`(注意尾随句点,它指的是cwd;从工作树的顶级目录运行它)。 (2认同)
  • @RobertSiemer“本地”是指_current directory_下的文件,该文件可能是其主git存储库以下。--porcelain解决方案列出了在_whole git repository_中找到的所有未跟踪文件(减去git忽略的文件),即使您位于其子目录之一内。 (2认同)

0xf*_*xfe 167

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

这是我做的:

  1. 对于脏状态:

    # Returns "*" if the current git branch is dirty.
    function evil_git_dirty {
      [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*"
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于未跟踪的文件(注意--porcelain标志为其git status提供了可用的可解析输出):

    # Returns the number of untracked files
    
    function evil_git_num_untracked_files {
      expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l` 
    }
    
    Run Code Online (Sandbox Code Playgroud)

虽然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)
Run Code Online (Sandbox Code Playgroud)

注意:2>/dev/null筛选出错误消息,以便您可以在非git目录上使用这些命令.(他们只会返回0文件计数.)

编辑:

以下是帖子:

将Git状态信息添加到终端提示符

改进了Git启用的Shell提示符

  • 值得注意的是,git bash完成时带有一个shell函数,用于完成你正在使用的提示 - "__git_ps1".它显示分支名称,包括特殊处理,如果您正在进行rebase,am-apply,merge或bisect.您可以设置环境变量"GIT_PS1_SHOWDIRTYSTATE"以获取未分阶段更改的星号以及分阶段更改的加号.(我想你也可以用它来表示未跟踪的文件,并给你一些`git-describe`输出) (8认同)
  • 警告:如果索引中已有更改,则`git diff --shortstat`将给出误报. (8认同)
  • 不 - 瓷器意味着输出是_humans_并容易打破!请参阅@ChrisJohnsen的回答,它正确地使用了稳定的,脚本友好的选项. (7认同)
  • 来自git-status手册页的@mike关于瓷器选项:"以易于解析的格式为脚本提供输出.这类似于短输出,但在Git版本中保持稳定,无论用户配置如何. " (6认同)
  • `git status --porcelain`是首选,因为`git diff --shortstat`不会捕获新创建的空文件.您可以在任何干净的工作树中尝试:`touch foo && git diff --shortstat` (4认同)
  • @mike,你错了.`--porcelain`选项为指南创建了一个特定的显式异常,保证命令输出格式在各个版本中都是稳定的,因此脚本可以依赖它.该选项由多个git命令实现,总是具有相同的含义:使输出适合脚本. (2认同)
  • grep中最未充分利用的函数之一是`-c`,你不需要将grep传递给`wc -l` (2认同)

ben*_*ado 136

假设您使用的是git 1.7.0或更高版本...

在阅读了本页面上的所有答案和一些实验后,我认为正确和简洁的正确组合的方法是:

test -n "$(git status --porcelain)"
Run Code Online (Sandbox Code Playgroud)

虽然git允许在跟踪,忽略,未跟踪但未签名等等之间存在很多细微差别,但我相信典型的用例是自动构建脚本,如果您的结账不干净,您希望停止所有内容.

在这种情况下,模拟程序员会做什么是有意义的:输入git status并查看输出.但是我们不想依赖特定的单词出现,所以我们使用--porcelain1.7.0中引入的模式; 启用时,干净的目录不会导致输出.

然后我们test -n用来查看是否有任何输出.

如果工作目录是干净的,则此命令将返回1;如果要提交更改,则此命令将返回0.如果您想要相反,可以将其更改-n为a -z.这对于将其链接到脚本中的命令很有用.例如:

test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"
Run Code Online (Sandbox Code Playgroud)

这有效地说"要么没有变化要么发出警报"; 根据您编写的脚本,这个单行可能比if语句更可取.

  • 感谢您回答这个问题而不是一直闲聊,从不提供明确的答案. (5认同)
  • 对于手动部署脚本,请将其与 `test -n "$(git diff origin/$branch)"` 结合使用,以帮助防止部署中允许本地提交 (2认同)

Dea*_*her 14

VonC回答的一个实现:

if [[ -n $(git status --porcelain) ]]; then echo "repo is dirty"; fi
Run Code Online (Sandbox Code Playgroud)


mlo*_*o55 7

看了几个答案......(并且在*nix和windows上有各种问题,这是我的要求)......发现以下效果很好......

git diff --no-ext-diff --quiet --exit-code
Run Code Online (Sandbox Code Playgroud)

检查*nix中的退出代码

echo $?   
#returns 1 if the repo has changes (0 if clean)
Run Code Online (Sandbox Code Playgroud)

检查窗口$中的退出代码

echo %errorlevel% 
#returns 1 if the repos has changes (0 if clean) 
Run Code Online (Sandbox Code Playgroud)

来自https://github.com/sindresorhus/pure/issues/115 感谢@paulirish对该帖子的分享

  • 很好的简短回答。很高兴您还提到了如何在 Linux 和 Windows 中检查退出代码,这节省了另一个 Google 搜索。旁注:您可以省略“--exit-code”,因为它是由“--quiet”暗示的。 (3认同)

Von*_*onC 6

git status为什么不使用脚本封装 ' :

  • 将分析该命令的输出
  • 将根据您的需要返回适当的错误代码

这样,您就可以在脚本中使用“增强”状态。


正如0xfe在他的出色回答中提到的那样,git status --porcelain在任何基于脚本的解决方案中都非常有用

--porcelain
Run Code Online (Sandbox Code Playgroud)

以稳定、易于解析的脚本格式提供输出。
目前这与 相同--short output,但保证将来不会改变,从而使脚本安全。


Rob*_*anu 6

一种 DIY 可能性,已更新以遵循0xfe的建议

#!/bin/sh
exit $(git status --porcelain | wc -l) 
Run Code Online (Sandbox Code Playgroud)

正如Chris Johnsen所指出的,这只适用于 Git 1.7.0 或更高版本。

  • 问题在于,您无法可靠地期望未来版本中出现字符串“工作目录干净”。--porcelain 标志用于解析,因此更好的解决方案是: exit $(git status --porcelain | wc -l) (6认同)
  • `git status --porcelain` 和 `git status --short` 均在 1.7.0 中引入。`--porcelain` 专门引入它是为了允许 `git status --short` 将来改变其格式。因此,“git status --short”会遇到与“git status”相同的问题(输出可能随时更改,因为它不是“管道”命令)。 (3认同)