Git索引中已修改文件的数量

6

如何查找索引中修改文件的数量?也就是说,在运行git status时显示为“修改”的文件。

我知道很多可视化的git工具和shell插件都可以做到这一点,还有在提示符旁边显示计数的功能,但我只是不知道如何在命令行上以合理的方式实现它。


不确定是否理解问题,您是在寻找类似于 git status -s -uno | wc -l 的东西吗? - mpromonet
1
看起来那就是答案。 - Rikki Gibson
3个回答

17

你可以使用以下代码获取已修改文件的数量:

git status -s -uno | wc -l

根据git status文档-s以简短的格式输出,-uno不显示未跟踪的文件。


3

简短概述

您可能需要了解 工作树 vs HEAD 或者 索引 vs HEAD,或者 工作树 vs 索引加上索引 vs HEAD。如果您想要将这两个比较分开,请注意无法在一个步骤中完成。

长篇描述

具体问题有几种可能的答案。请注意,在下面的所有差异命令中,如果您不关心文件中的特定更改,则可以使用--name-only。状态字母(添加、删除、修改等)对于决定添加 --diff-filter 以仅选择特定类型的更改非常有用。例如,如果您想知道有多少个文件严格地被修改,不计算添加或删除的文件,则可以过滤 M

  1. git diff --cached --name-status HEAD | wc -l
  2. git diff --name-status HEAD | wc -l
  3. git diff --name-status | wc -l
  4. git status -s -uno | wc -l (如mpromonet的评论所示)。

每个命令都会产生不同的结果:

  1. 比较HEAD和索引:如果你现在运行git commit,与当前的HEAD提交相比,你将做出什么不同的提交?也就是说,你现在有一个当前的提交,如果你创建一个新的提交,当前的提交将成为新提交的父提交。会有什么不同?

    (记住,索引表示要进行的下一个提交。它最初包含与HEAD完全相同的文件副本。每次你使用git add添加文件时,都会将文件从工作树中复制回索引中。因此,这是将要提交的内容与你的HEAD提交进行比较。特别地,在这里,你可以省略名称HEAD--cached会假定HEAD。)

    在长的git status输出中,这些内容出现在第一部分:Changes to be committed

  2. 比较HEAD和工作树。这些是在工作树中修改但未准备提交的文件。在更长的git status输出中,这些通常出现在第二部分:Changes not staged for commit——但请看接下来的内容。

  3. 比较索引和工作树。这些文件也是在工作树中修改的,但是这次它们与已经复制回索引的文件相比发生了变化。在索引与HEAD提交匹配的情况下,#2和#3会产生相同的文件列表。但是假设READMEHEAD中为版本H(表示Head)。你修改了README并使用git add README将版本W(表示Work-tree)复制到版本I(表示Index)中。然后你又修改了版本W。现在所有三个版本都不同了!使用git status --shortgit status -s,你会在输出中看到MM README:它被修改了两次。

    这一部分的输出实际上是出现在git status输出的后半部分,即Changes not staged for commit部分。

  4. 比较HEAD与索引,然后比较索引与工作树,最后以汇总的组合格式打印每个文件的名称和状态,对于每个文件使用两个字母。

为了清晰说明,考虑一个只有一个初始提交并且包含一个文件的存储库。该文件名为README,初始提交版本包含文本Read me.
$ git init
Initialized empty Git repository in ...
$ echo 'Read me.' > README
$ git add README
$ git commit -m initial
[master (root-commit) a9362c4] initial
 1 file changed, 1 insertion(+)
 create mode 100644 README
$ echo 'Please read me.' > README
$ git add README
$ echo 'Read me, for I am very readable.' > README

现在有三个活跃版本的文件README,并且:
$ git status -s
MM README
< p >长版本的 git status 向我们展示了 README 已经准备好提交,但是有未暂存的更改:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   README

看看如果我们将初始文本放回,然后比较HEAD和工作树会发生什么:

$ echo 'Read me.' > README
$ git diff --name-status HEAD
$

当前提交与工作树匹配,因此这里没有任何区别。如果你使用git add README,短状态从MM README变为空:
$ git status -s
MM README
$ git add README
$ git status -s
$

如果你想知道“添加和提交所有文件会得到什么”,你需要将 HEAD 与工作树进行比较。如果你在想“现在提交会得到什么”,你需要将 HEAD 与索引进行比较。


感谢您提供这么详细的答案。让我确认一下术语是否正确:HEAD 是当前检出的提交,就像当您运行 git status 命令时输出 "On branch $foo" 一样。索引是如果您运行 git commit 命令将被转换为提交的内容。工作树基本上是文件系统上项目的状态。如果我有任何混淆,请纠正我。 - Rikki Gibson
1
没错,完全正确。更详细地说,在你的情况下,HEAD 通常包含分支名称 $foo,然后分支名称包含提交哈希值,这使得查找哈希值成为一个两步过程——但大多数情况下,Git 只是从 HEAD 查找提交哈希值,就好像它是一个整体一样。 - torek

3

由于这个问题是关于查找更改数量的,有几个git命令可以原生地执行此操作,而无需将| wc -l添加到您的命令中。

您可以使用git diff并使用以下参数:

  • --stat - 生成差异统计信息
  • --numstat - 显示以十进制表示的添加和删除行数
  • --shortstat - 仅显示--stat的最后一行
$ git diff --stat

src/models/models.ts | 5 +++++
src/utils/git.ts     | 9 ++++++---
2 files changed, 11 insertions(+), 3 deletions(-)

$ git diff --numstat

5       0       src/models/models.ts
6       3       src/utils/git.ts

$ git diff --shortstat

2 files changed, 11 insertions(+), 3 deletions(-)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接