git中的索引、缓存和暂存区有什么区别?

55

这两个东西是一样的吗?如果是,为什么有这么多术语?!

此外,我知道有一个叫做 Git Stash 的工具,可以在不提交到仓库的情况下将更改暂时存储到你的本地副本中。我觉得这个工具非常有用,但是它的名称与 Git 中的一堆其他概念非常相似,这非常令人困惑!!


不要忘记“added”,因为Android Studio在其Git版本控制UI中使用它。 - SMBiggs
@ScottBiggs "added" 是什么意思? - allyourcode
我仍然是一个对Git感到困惑的新手。在“提交”之前,需要执行“添加”操作,而我也对“存储”(Stash)这个术语感到困惑(又增加了一个术语)。 - SMBiggs
3个回答

47
索引/阶段/缓存是同一件事情 - 至于为什么有这么多术语,我觉得索引是最初的术语,但人们发现它很容易混淆,所以引入了其他术语。我同意,这在一开始有时会让事情变得有点混乱。
Git的stash功能是一种储存“正在进行中”的工作, 而你现在不想提交到特定存储区域(一个commit对象),基本的 stash 命令将存储对工作目录进行的未提交更改(包括缓存/阶段和未缓存/未暂存的更改),然后回滚工作目录到HEAD版本.
除了储存缓存中未提交��更改外,这与索引/阶段/缓存没有太大关系。
这使您可以快速保存一个脏的工作目录和索引的状态,以便在干净的环境中执行不同的工作。稍后,您可以获取stash对象中的信息并将其应用于您的工作目录(即使工作目录本身处于不同的状态)。
官方的git stash手册详细而易懂,并且有关于如何使用stash的很好的示例。

4
git stash与其他命令不同:它更像是一个“匿名提交”。 - Peter Tillemans
2
在我的中间编辑中,我试图表明,无论是暂存的更改还是未暂存的更改都包含在存储区中。但看起来我不小心删除了一些内容,使答案不够清晰。希望现在已经修复了。 (@allyourcode 是个用户名,没有翻译) - Michael Burr
4
但是如果索引可以在合并期间在其中存储多个阶段,那么索引和阶段之间是否存在技术上的区别呢?索引是一个文件,而阶段是工作文件系统的抽象表示,并使用唯一的文件格式在索引中进行编码(在合并期间索引可以有多个阶段)。但在大多数情况下,这些词是可互换的。 - Alexander Bird
1
如果“索引/阶段/缓存是同一件事”,为什么git ls-files --cached返回的列表比git diff --cached --name-only长得多?后者显示将包含在下一个提交中的文件,即已暂存的文件。 - Steve Pitchers
git ls-files --cached 显示被跟踪的文件以及索引/暂存区/缓存中的文件(--cache选项是git ls-files的默认行为)。我不确定这种行为的理由,但这就是它的作用。git diff --cached --name-only 只显示索引/暂存区/缓存中的文件。 - Michael Burr
显示剩余7条评论

23

非常令人困惑。这三个术语可以互换使用。以下是我对为何称其为这些名称的看法。Git索引:

  • 是一个二进制文件.git/index,它是所有已跟踪文件的索引
  • 用作提交的暂存区
  • 包含文件的缓存SHA1哈希(加快性能)

重要的一点是,索引/缓存/暂存区包含源代码控制下的所有文件列表,即使是未更改的文件。不幸的是,像“将文件添加到索引”或“文件已暂存到索引”等短语可能会误导地暗示索引仅包含更改的文件。

以下是一个演示,显示git索引包含所有文件列表,而不仅仅是更改的文件:

# setup
git init

echo 'x' > committed.txt
git add committed.txt
git commit -m 'initial'

echo 'y' > staged.txt
git add staged.txt

echo 'z' > working.txt

# list HEAD
git ls-tree --name-only -r HEAD
# committed.txt

# list index
git ls-files
# committed.txt
# staged.txt

# raw content of .git/index
strings .git/index
# DIRC
# committed.txt
# staged.txt
# TREE

# list working dir
ls -1
# committed.txt
# staged.txt
# working.txt

额外阅读:

https://www.kernel.org/pub/software/scm/git/docs/technical/racy-git.txt

Git索引包含什么?


太好了!我想你的意思是ls -l而不是ls -1。 - user5389726598465
一个重要的注意事项是,索引/缓存/阶段包含源代码控制下的所有文件的列表,即使是未更改的文件也包括在内。这句话对我来说非常重要。我正在阅读https://www.atlassian.com/git/tutorials/undoing-changes/git-reset ,它说:“--mixed是默认的操作模式。引用指针被更新。暂存索引被重置为指定提交的状态。” 我就想,啥意思?难道暂存索引不应该是空的吗?因此,我认为如果有任何添加或提交的内容,则会出现在索引中。当我们添加已更改的文件时,它会更新文件的SHA,对吗? - iRestMyCaseYourHonor
@user5389726598465 -- ls -1 是有效的,并且与他粘贴的输出匹配。(man页面: "-1 强制每行输出一个条目。" vs "-l 以长格式列出。") - boweeb
1
@iRestMyCaseYourHonor -- 是的,那是一个重要的注意点。请记住,git 不是通过在提交中存储差异,而是存储内容的快照来工作。请参阅 atlassian.com/git/tutorials/saving-changes/git-commit 的相关部分,标题为“快照,而不是差异”。有了这个想法,就有意义了,索引永远不应该为空(除非当然存储库没有提交或暂存的内容)。 - boweeb
关于“字符串”的一个小提示,它的默认设置仅显示 4 个或更多 ASCII 字符的序列,因此如果您尝试使用类似于 foo 的较短文件名,则不会打印出来。strings -n 3 会打印出来,但您也会得到一些垃圾信息。 - Zach Young

1

历史

https://dev59.com/0mw15IYBdhLWcg3wSJo3#6718135

混淆: --cache vs --index 等等。

来自我修改过的 man gitcli: enter image description

add/index/stage/cache

索引文件:

  • 是所有已跟踪的文件的索引
  • 用作提交的暂存区
  • 包含文件的缓存d SHA1哈希值(提高了性能)

来自man git:
$GIT_INDEX_FILE设置索引文件。 如果未指定, 将使用$GIT_DIR/index

索引文件是二进制文件。
在nvim中打开时,这是部分截图:
enter image description here

当使用名为fugitive的插件在nvim中打开时:
enter image description here
内容与git status的输出非常相似,而不是strings .git/index

相关命令

  1. git add ("将文件添加/暂存索引中")
  2. git restore --staged ( --staged | 恢复索引 )
  3. git rm --cached (--cached | 仅从索引中删除文件)

暂存 vs 跟踪

  • 未跟踪的更改不在Git中。
  • 未暂存的更改在Git中,但未标记为提交。
  • 已暂存的更改在Git中,并标记为提交。

git ls-files

            1.
                -c, --cached  ( cache:  obsolete for index) 
                    Show cached files in the output
                    (default)

                -s, --stage
                    Show staged (git add) files'  
                                            mode bits,
                                            object name
                                            stage number  
                -u, --unmerged
                    (forces --stage)
                    Show unmerged files in the output

                -d, --deleted 

                -m, --modified   

                -k, --killed
                    Show files on the filesystem
                    that need to be removed due to
                    file/directory conflicts
                    for checkout-index to succeed. 
            2.
            -o, --others
                other (i.e. untracked) files

                --directory
                    If a whole directory is classified as "other",
                    show just its name  (with a trailing slash)
                    and not its whole contents.

                    --no-empty-directory
                        Do not list empty directories.
                        Has no effect without --directory.

进一步阅读

https://github.blog/2021-11-10-make-your-monorepo-feel-small-with-gits-sparse-index/

概览

输入图片说明


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