【问题标题】:Strange output of "git diff", "git diff HEAD" and "git diff --staged"?“git diff”、“git diff HEAD”和“git diff --staged”的奇怪输出?
【发布时间】:2020-05-27 20:53:00
【问题描述】:

git diff 主要有 3 个版本:

  • git diff - WORKING DIRECTORYSTAGE 之间的区别
  • git diff --staged - HEADSTAGE 之间的区别
  • git diff HEAD - HEAD工作目录
  • 之间的区别

以上是我在网上从不同的人那里找到的几乎每个地方的定义

我按以下顺序对 3 个文件执行了某些提交:

ce6f5bb (HEAD -> master) 6th commit, file1
c1c67da 5th commit, file3    
ea51776 4th commit, file1 file2    
001675b 3rd commit, file1 file2    
ec04f53 2nd commit, file2    
21cb6c1 1st commit, file1  

一个。 file2 在工作目录中修改
b.没有任何准备提交
c。 file1 & file3 未修改


我的查询是:

1。混帐差异

    git diff
    diff --git a/file2.txt b/file2.txt
    index 21106bf..c755a1e 100644
    --- a/file2.txt
    +++ b/file2.txt
    @@ -1,3 +1,4 @@
     123
     345
     678
    +90.    

即使暂存区是空的,为什么会显示差异?


2。 git diff 头

    git diff
    diff --git a/file2.txt b/file2.txt
    index 21106bf..c755a1e 100644
    --- a/file2.txt
    +++ b/file2.txt
    @@ -1,3 +1,4 @@
     123
     345
     678
    +90.    

如果 LAST COMMIT (HEAD) 与 file1 相关,那么为什么会显示 file2 的差异?
HEAD 不包含任何与文件2



暂存文件2之后

3。混帐差异

它不显示任何东西!
(我假设它只会在文件被暂存时显示差异,并且在工作目录中也进行了一些 除了暂存版本之外的更改)
那么如果是这样的话,那么为什么 diff 会显示在 1.


4。 git diff --staged

    git diff
    diff --git a/file2.txt b/file2.txt
    index 21106bf..c755a1e 100644
    --- a/file2.txt
    +++ b/file2.txt
    @@ -1,3 +1,4 @@
     123
     345
     678
    +90.    

如果 HEAD 指向 file1,为什么会显示 file2 的差异?



我在下面创建了这张图片(注意:另一个场景。与上面不同)

对于git diff HEAD,我的猜测是对于每个跟踪的文件,HEAD 将继续向后移动,直到找到提交的该文件的最新版本,以便与工作目录中的文件进行比较

如果我们考虑如下新场景,那么对于git diff HEAD,它是否像我假设的那样?

【问题讨论】:

  • 暂存区永远不会是空的,除非您有意删除了所有内容。暂存区默认为 HEAD 的内容。本质上,如果您进行允许“空”提交的提交,将提交的内容是空的,即没有进行任何更改,但在内容方面永远不会为空。暂存区包含提交时将提交的快照,因此它默认为 HEAD 的内容。
  • 与 HEAD 相比,您的 HEAD 和工作目录之间的差异表明您已经更改了工作目录中的文件。根据您的标准列表,其他两个文件未更改,因此未显示。
  • 我认为让您感到困惑的是,当 git 列出差异和状态时,它会忽略不引入更改的所有内容。这就是为什么,即使暂存区 包含 默认情况下 HEAD 中的所有内容,如果您要求 git 显示其内容,它也不会显示任何内容,因为两者之间没有 区别 HEAD 和暂存区。
  • 例如,执行以下操作。确保您有一个原始的结帐,工作文件夹中没有更改,暂存区也没有更改。然后通过在一行中添加 1 个字母来修改文件。通过git add . 添加它,然后执行git diff --staged。你会看到变化。然后,再次修改文件,删除您添加的字母。添加它,然后再次进行差异。即使您添加了两次,它也应该再次显示没有变化。
  • 提交始终是一个完整的快照,但它不会为所有文件创建新副本,它会引用数据库中的现有对象以获取未更改的文件,但您可以说commit 包含所有文件,而不仅仅是那些被更改的文件。

标签: git github version-control diff git-diff


【解决方案1】:

您犯了一个根本性错误,然后将此错误传播到您的各种命令中。

错误在于您将提交视为更改。提交不是一组更改。提交包含文件的快照。此外,暂存区实际上从来都不是empty1它只是匹配当前提交,最初。

文件file1.txtfile2.txtfile3.txt存在于:

  • 您的工作树,作为普通文件;
  • 索引/暂存区,作为 Git 特殊提交格式的文件,准备提交;
  • 每次提交。

每个文件的每个副本都可以匹配同一文件(或任何其他文件)的其他副本,也可以不同。

名称HEAD 选择一个特定的提交。2 在您的各种测试开始时,名称HEAD 选择提交ce6f5bb。因此,除了早期提交中的文件之外,此时您和 Git 可以使用三个名为 file1.txt 的文件:

  • ce6f5bb:file1.txt,又名HEAD:file1.txtfile1.txt 的此副本已冻结为提交,无法更改。
  • :file1.txtfile1.txt 的这个副本在索引/暂存区。您可以随时将其替换为新副本。
  • file1.txt:这只是一个普通的文件。它实际上根本不是 in Git。它是您工作树中的常规文件。

还有三份file2.txt和三份file3.txt

不带参数运行git diff 会将HEAD 中的所有三个文件与工作树中的所有三个文件进行比较。只有那些不同的才会在输出中提及。

运行git diff --stagedgit diff --cached 会将HEAD 中的所有三个文件与暂存区中的所有三个文件进行比较。只有那些不同的才会在输出中提及。

运行git diff HEADHEAD 中的所有三个文件与工作树中的所有三个文件进行比较。只有那些不同的才会在输出中提及。

请注意,当您使用 git log -pgit show 查看提交时,Git 会创建父提交的快照(其文件)与该提交的快照的 git diff。您看到的 diff 中只提到了那些不同的文件。所以它看起来提交存储了更改,但实际上,它只是存储了一个快照。

还要注意,git status 运行两个 git diffs:一个比较 HEAD 与 staging-area,即运行一个 git diff --staged,并且只提及文件名,而不显示差异。这些是为提交文件暂存的更改。第二个差异比较索引与工作树,即执行git diff,并仅提及文件名。这些是未为提交暂存的更改


1暂存区可以完全是空的,并且在一个新的存储库中,其中还没有文件,而且还没有git add-ed。你也可以git rm每个文件,这会导致暂存区为空。但通常情况下,它充满了来自HEAD 提交的文件副本,直到您使用git add 将这些文件替换为工作树中的文件。

2关于HEAD这个特殊名称可以问Git两个问题:

git rev-parse HEAD

问 Git HEAD 代表什么哈希 ID,即,当前提交是什么?这是 git diff 所问的。或者:

git symbolic-ref HEAD
git rev-parse --symbolic-full-name HEAD

问 Git HEAD 代表什么分支名称,即 git status 会说我在哪个分支上?git commit 会问这个问题,例如,当它去的时候更新分支名称。

【讨论】:

  • 本质上,如果你把 git staged snapshot 看成是一个实际的舞台,用来制作一帧一帧的电影,那么 git 实际上是使用一个摄像头来拍摄整个舞台的完整快照里面的一切。许多人认为 git 记录的“变化”类似于关于如何为下一张照片准备舞台的手稿说明。 IE。 “将椅子向左移动 2 英寸”。 Git 不会记录,而是有 2 张舞台的完整照片,其中一张椅子在左侧 2 英寸处。
  • 魔法来自许多 git 命令,这些命令将根据需要计算出这些快照之间的差异,因此看起来 git 再次记录了更改,但实际上是在需要。
  • @torek,所以在阅读了您的回答后,我认为 commit ce6f5bb 将包含所有 3 个文件 (file1, file2, file3) 即使在第 6 次/最新提交中只有 file1 是 git add-ed 和 git commit-ed ?
  • 所以认为 LATEST COMMIT 将包含 (newly TRACKED files if any + ALL OF previuly TRACKED FILES of previous提交)
  • 是的:索引/暂存区域从您刚刚签出或刚刚创建的提交中的所有文件开始。因此,无论您在其中替换或添加,remaining 文件也会进入下一次提交。在每个git commit 之后,暂存区与新提交匹配。
猜你喜欢
  • 1970-01-01
  • 2017-03-07
  • 2012-11-13
  • 2017-02-14
  • 1970-01-01
  • 2015-02-15
  • 1970-01-01
  • 2020-02-03
  • 2020-05-17
相关资源
最近更新 更多