代码之家  ›  专栏  ›  技术社区  ›  Robert Munteanu

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

  •  225
  • Robert Munteanu  · 技术社区  · 14 年前

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

    1. 未跟踪的文件

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

    13 回复  |  直到 14 年前
        1
  •  179
  •   Izkata    10 年前

    我是这样做的:

    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 它提供了很好的可解析输出):

      # 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 0 对于文件计数。)

    编辑 :

    Adding Git Status Information to your Terminal Prompt

    Improved Git-enabled Shell Prompt

        2
  •  418
  •   Eduard Wirch    7 年前

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

    不幸的是,日常使用的Git命令都是陶瓷命令,因此大多数Git用户可能不熟悉管道命令。瓷器和水管之间的区别主要体现在 git manpage (见标题为 High-level commands (porcelain) Low-level commands (plumbing)


    git diff-index (比较索引(可能还有工作树的跟踪位)和其他树(例如。 HEAD )),也许吧 git diff-files git ls-files (a)列出文件;e、 g.列出未跟踪、未忽略的文件)。

    (注意,在下面的命令中, HEAD -- 否则命令 fails 如果有一个名为

    git diff-index --quiet --cached HEAD --
    
    • 如果它以 0 1 表示存在差异)。

    要检查工作树是否具有可以暂存的更改,请执行以下操作:

    git diff-files --quiet
    
    • 退出代码与的相同 git差异索引 ( 0 ==无差异; ==差异)。

    检查工作树中的索引和跟踪文件的组合是否相对于

    git diff-index --quiet HEAD --
    
    • 这就像是前两者的结合。一个主要的区别是,如果您在工作树中撤消了一个阶段性的更改(返回到工作树中的内容),它仍然不会报告任何差异

    你还提到了未追踪的文件。您可能意味着未跟踪和未忽略,或者您可能意味着只是简单的未跟踪(包括忽略的文件)。不管怎样, git ls文件

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

    git ls-files --others
    

    对于未跟踪和未忽略的:

    git ls-files --exclude-standard --others
    

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

    test -z "$(git ls-files --others)"
    
    • 如果它以 0 1

    有一个小的机会,这将转化为不正常的出口 git ls文件 “无未跟踪文件”报告(两者都会导致上述命令的非零退出)。更健壮的版本可能如下所示:

    u="$(git ls-files --others)" && test -z "$u"
    
    • git ls文件 传播出去。在这种情况下,非零出口可能意味着存在未跟踪的文件,也可能意味着发生了错误。如果要将错误结果与“无未跟踪文件”结果合并,请使用 test -n "$u" (出口在哪里 0

    另一个想法是使用 --error-unmatch 1 )出现错误时(退出非零,但可能 128 ). 但是检查 0 与。 与非零退出码相比,可能相当稳健:

    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文件 举个例子 --exclude-standard

        3
  •  152
  •   benzado    10 年前

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

    test -n "$(git status --porcelain)"
    

    在这种情况下,模拟程序员将要做的事情是有意义的:键入 git status 再看看输出。但我们不想依赖于特定的词语出现,所以我们使用 --porcelain

    然后我们使用 test -n 看看是否有输出。

    如果工作目录是干净的,此命令将返回1,如果要提交更改,则返回0。你可以改变主意 -n -z 如果你想要相反的结果。这对于将其链接到脚本中的命令非常有用。例如:

    test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"
    

    这实际上是在说“要么没有任何改变,要么引发警报”;这一行可能比if语句更好,这取决于您正在编写的脚本。

        4
  •  15
  •   Community Egal    7 年前

    来自的实现 VonC 的答案:

    if [[ -n $(git status --porcelain) ]]; then echo "repo is dirty"; fi
    
        5
  •  8
  •   mlo55    8 年前

    看了一些答案(在*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的分享

        6
  •  4
  •   Community Egal    7 年前

    为什么不封装 git status 用一个脚本:

    • 将根据需要返回相应的错误代码

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


    0xfe excellent answer , git status --porcelain

    --porcelain
    

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

        7
  •  4
  •   Community Egal    7 年前

    0xfe 的建议

    #!/bin/sh
    exit $(git status --porcelain | wc -l) 
    

    Chris Johnsen ,这只适用于git1.7.0或更新版本。

        8
  •  2
  •   sorin    5 年前

    我经常需要一种简单的方法,如果在执行结束时有任何修改的跟踪文件或任何未跟踪的文件不被忽略,就可以使构建失败。

    到目前为止,我使用的最好的命令如下所示:

     test -z "$(git status --porcelain | tee /dev/fd/2)" || \
         {{ echo "ERROR: git unclean at the end, failing build." && return 1 }}
    

    它可能看起来有点复杂,如果有人发现一个短的变种我会很感激

    • 如果一切正常,则无输出和成功退出代码
    • stderr上的错误消息解释了它失败的原因
    • 显示导致失败的文件的列表,请重新启动。
        9
  •  2
  •   oliver    5 年前

            set -eu
    
            u="$(git ls-files --others)"
            if ! git diff-index --name-only --quiet HEAD -- || [ -z "${u:-}" ]; then
                dirty="-dirty"
            fi
    

    当不使用set-e或等价物执行时,我们可以执行 u="$(git ls-files --others)" || exit 1 (如果对已用函数有效,则返回)

    之后,我们可以检查这两个属性,并设置一个变量(或其他)。

        10
  •  1
  •   docwhat    11 年前

    为了找出 任何 存储库中存在未跟踪的文件:

    # Works in bash and zsh
    if [[ "$(git status --porcelain 2>/dev/null)" = *\?\?* ]]; then
      echo untracked files
    fi
    

    grep ,并且不需要检查您是否在git存储库中。对于shell提示等非常方便。

        11
  •  1
  •   Linus Arver    8 年前

    你也可以这样做

    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.
    

    . 警告:未跟踪的文件不被认为是“脏的”,因为正如manpage所说,它只关心工作树。

        12
  •  1
  •   Asclepius    4 年前

    肮脏的状态 = :

    git add --all
    git diff-index --exit-code HEAD
    

    评论:

    • add --all , diff-index 不会注意到未跟踪的文件。
    • 通常我跑步 git reset 在测试完错误代码后,把所有的东西都放回去。
    • 考虑 --quiet 而不是 --exit-code 以避免输出。
        13
  •  0
  •   Alex Gray    9 年前

    从这条线索可能会有更好的答案组合。。但这对我有用。。。为了你的 .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
    
        14
  •  -3
  •   codyc4321    7 年前

    这是最好的,最干净的方法。由于某些原因,选定的答案对我不起作用,它没有接收到未提交的新文件的更改。

    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
    }