Git索引中存在未使用`add`命令添加的文件。

huangapple go评论56阅读模式
英文:

Git Index has files without using `add`

问题

git索引允许我们指定要放入新tree对象的文件 - 这样的tree对象是任何新创建的commit对象将指向的。

我知道使用git add <filename>将文件放入索引,以便生成一个tree

然而,索引似乎在文件添加到索引之前就存储了这些文件。运行以下命令后,即使一个"clean"目录也会显示与由HEAD指向的提交相同的文件。

git ls-files --stage

(我认为这会显示index中的文件,因为stage index 同义)

为什么git会在索引中存储"未添加"的文件?这些文件不是通过查看HEAD可用吗?这似乎是多余的。


当阅读某些man页面时,HEAD、索引和工作树之间的区别变得更加模糊。例如,这是从man git-restore中提取的。

> 默认情况下,如果给出了--staged,内容将从HEAD恢复,否则从索引恢复

  • 我认为如果编辑了b.txt但未将其添加到索引(即git status显示红色字母),那么index中的b.txt版本与HEAD中的版本相同。然而,git restore --staged -- b.txt 不起作用,而git restore -- b.txt将工作树恢复到HEAD提交中的版本。
  • 如果stage index 同义,那么为什么--staged在这个man页面中指的是HEAD
英文:

The git index allows us to specify the files that go into a new tree object - such a tree object is what any newly created commit object will point to.

I'm aware that using git add &lt;filename&gt; puts a file into the index so that a tree can be generated.

However, the index seems to store files even before they have been added to the index. After running the following command, even a "clean" directory will display all the same files as the commit pointed to by HEAD.

git ls-files --stage

(I assume that this displays the files in the index because stage is synonymous with index)

Why would git store "un-added" files in the index? Aren't these files available by looking at HEAD? This seems redundant.


The distinction between HEAD, index, and working tree gets even murkier when reading certain man pages. For example, this is from man git-restore.

> By default, if --staged is given, the contents are restored from HEAD, otherwise from the index

  • I would think that if b.txt is edited but not added to the index (i.e. git status shows red letters), then the version of b.txt in the index is the same as in HEAD. However, git restore --staged -- b.txt does nothing whereas git restore -- b.txt restores the working tree to the version in the HEAD commit.
  • If stage is synonymous with index then why would --staged refer to HEAD in this man page?

答案1

得分: 2

不要使用 git ls-files --stage 命令来检查你暂存的文件,使用 git status


当一个人和另一个人讨论关于 git 时,通常会用 "索引" 来指代你在仓库中 已经暂存的更改

但是从 git 内部的角度来看:"索引" 其实是 当前 HEAD 提交的内容 加上你已经暂存的更改。

举个简单的例子:当你运行 git diff --cached 命令时,它比较的是 索引 和当前 HEAD 提交,那些没有被修改的文件不会被报告为从索引中 "丢失" 的。

git ls-files --stage 命令只会报告索引的内容(git 内部的索引)。在某些特定情况下,可能会有人对这些信息感兴趣,但通常用户会使用 git status


关于 git restore:我认为有关 git restore--staged 选项和 git diff--cached 选项存在混淆。

([编辑] 我也会说,在 git 团队的部分中,将 -s-S--source--staged 这些选项愉快地结合在一起,实际上相当误导人,我在搞清楚这个命令的含义之前也头疼了好几次。尽管我认为这些用例是有意义的。)

请注意,git restore 中的 --staged 选项的含义 非常不同:它指定了 你想要写入文件的位置,也就是说 "在 git 存储中,在索引中" 与 "在磁盘上,在工作树中"(我的 "与" 也是误导:实际上你可以使用 git restore -SW 来同时指定这两个选项)。

引用文档:

> -W, --worktree
> -S, --staged
>
> 指定还原的位置。如果没有指定任何选项,默认情况下会还原到工作树。指定 --staged 选项只会还原到索引。指定两者都会同时还原。

你引用的文档是关于 -s|--source 选项的:如果指定了 -S|--staged 选项,那么 --source 的默认值 就不同。

所以:如果一个文件 b.txt 没有暂存的更改,这意味着该文件在索引中的内容与 HEAD 的内容相同,正如你正确观察到的那样,git restore --staged -- b.txt 不会产生任何效果。

--staged 的用法是针对其他情况的:

  • 如果文件 b.txt 有暂存的更改,那么 git restore --staged -- b.txt 将会 取消已暂存的更改
  • git restore -s that/other/commit --staged -- b.txt 会将 b.txt 的内容从 that/other/commit 放入索引中,而不改变工作树
  • 等等 ...
英文:

Don't use git ls-files --stage to check your staged files, use git status.


When a human talks to another human about git, she/he generally uses "the index" to refer to the changes you have staged in your repo.

But from the point of view git internals: "the index" is actually the content of the current HEAD commit plus the changes you have staged.

To give a simple illustration: when you run git diff --cached, which compares the index with the current HEAD commit, files that haven't been modified are not reported as "missing" from the index.

git ls-files --stage just reports the content of the index (the git internal one). There are some specific cases when one may be interested in that information, but generally users are looking for git status.


Regarding git restore: I think there is a confusion between the --staged option for git restore and the --cached option for git diff.

([edit] I will also say that it is pretty misleading, on the git team part, to have a command which happily combines -s,-S,--source and --staged, and I also had a few headaches before I figured out what was what with that command. The use cases make sense though, imho.)

Note that the meaning of --staged for git restore is very different : it specifies where you want to write your files, as in "in git storage, in the index" versus "on disk, in the worktree" (my "versus" is also misleading: you can actually ask for both with git restore -SW).

quoting the doc:

> -W, --worktree
> -S, --staged
>
> Specify the restore location. If neither option is specified, by default the working tree is restored. Specifying --staged will only restore the index. Specifying both restores both.

The documentation you quote is the one for -s|--source : if -S|--staged is specified, then the default value for --source is not the same.

So : if a file b.txt has no staged modifications, this means that the index content for that file is the same as HEAD's content, and, as you correctly observed, git restore --staged -- b.txt is a no-op.

The uses of --staged are the other cases:

  • git restore --staged -- b.txt would unstage staged changes if there were any
  • git restore -s that/other/commit --staged -- b.txt will put in the index the content of b.txt coming from that/other/commit, without changing the worktree
  • etc ...

huangapple
  • 本文由 发表于 2023年2月8日 12:08:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75381302.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定