英文:
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 <filename> 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.txtis edited but not added to the index (i.e.git statusshows red letters), then the version ofb.txtin theindexis the same as inHEAD. However,git restore --staged -- b.txtdoes nothing whereasgit restore -- b.txtrestores the working tree to the version in theHEADcommit. - If 
stageis synonymous withindexthen why would--stagedrefer toHEADin thismanpage? 
答案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.txtwould unstage staged changes if there were anygit restore -s that/other/commit --staged -- b.txtwill put in the index the content ofb.txtcoming fromthat/other/commit, without changing the worktree- etc ...
 
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论