gpt4 book ai didi

git - "git add file"和 "git checkout -- file"是对称的吗?

转载 作者:太空狗 更新时间:2023-10-29 13:20:59 24 4
gpt4 key购买 nike

我对git add filegit checkout -- file有以下理解(但不确定是否正确)。

每当我们使用文本编辑器编辑文件时,我们都会在工作目录中进行操作。每次我们可以通过执行staging area将文件移动到所谓的git add file_name。如果我们再次编辑文件(在git add之后),我们将在工作目录中更改文件,这样,在工作目录中,文件将处于"new"状态,而在staging area中,文件将处于“旧”状态。

当再次使用git add时,会将暂存区域中的文件置于"new"状态(工作目录中的状态)。

如果我们执行git checkout -- file_name,我假设我们从登台区域中获取一个文件,并使用它来覆盖工作目录中的文件。这样,我们可以将工作目录中的文件置于“旧”状态。这是正确的吗?

对我来说还不清楚的是,我们是否从暂存区复制或移动文件。换句话说,git checkout -- file是否会更改staging area中文件的状态。我们是否可以说在git checkout -- file之后,将暂存区中的文件的状态更改为暂存区中文件的先前状态?

最佳答案

几乎是对称的,但不是完全对称的。
的确,git add file将文件复制到阶段(也称为“索引”)。但是,这样做的方式有点怪异。
在git仓库中,所有内容都存储为git“对象”。每个对象都有一个唯一的名称,即SHA-1(像753be37fca1ed9b0f9267273b82881f8765d6b23这样的40个字符的字符串,该字符串来自我在这里使用的实际.gitignore)。该名称是通过计算文件内容上的哈希值构造的(或多或少,例如,为了确保您不会从目录树中生成文件或提交该文件而引起哈希冲突,有些头)。 Git假定无论内容如何,​​SHA-1都是唯一的:没有两个不同的文件,树,提交或带注释的标签将永远不会哈希到相同的值。
文件(和符号链接(symbolic link))是“blob”类型的对象。因此,对git repo中的文件进行了哈希处理,并且git在某个地方有一个映射:“名为.gitignore的文件”到“哈希值753be37fca1ed9b0f9267273b82881f8765d6b23”)。
在存储库中,目录树存储为“树”类型的对象。树对象包含名称(如.gitignore),模式,对象类型(另一棵树或blob)和SHA-1的列表:

$ git cat-file -p HEAD:
100644 blob 753be37fca1ed9b0f9267273b82881f8765d6b23 .gitignore
[snip]
提交对象为您(或git)提供了一个树对象,该对象最终为您提供了Blob ID。
另一方面,暂存区域(“索引”)只是一个文件 .git/index。该文件包含1名称(以有趣的略微压缩的形式压缩目录树), merge 冲突时的“阶段号”和SHA-1。实际的文件内容还是git repo中的blob。 (Git不在索引中存储目录:索引仅使用扁平化格式的实际文件。)
因此,当您这样做时:
git add file_name
git做到了这一点(或多或少,我故意掩盖过滤器):
  • 计算文件file_name(git hash-object -t blob)内容的哈希值。
  • 如果该对象尚未在存储库中,请将其写入存储库(使用-whash-object选项)。
  • 更新.git/index(或$GIT_INDEX_FILE),使其具有在file_name名称下的映射,以映射到从git hash-object出来的名称。这始终是“stage 0”条目(这是正常的,没有 merge 冲突的版本)。

  • 因此,文件不是真的在“临时”区域中,而是真正在仓库本身的“内部”!暂存区域中的内容是SHA-1映射的名称。
    相比之下, git checkout [<tree-ish>] -- file_name这样做:
  • 如果给定了<tree-ish>(提交名称,树对象ID等-基本上git可以解析为树),请通过将参数转换为树对象来从树中查找名称。使用这样定位的对象ID,在阶段0处更新索引中的哈希。(如果file_name命名一个树对象,则git递归地处理树所代表的目录中的所有文件。)通过创建阶段0条目,所有 merge 冲突file_name现在已解决。
    否则,请在索引中进行名称查找(如果file_name是目录,可能不确定git会读取工作目录,所以不知道会发生什么)。将file_name转换为对象ID(此时将是blob)。如果没有阶段0条目,除非给出了-m--ours--theirs选项,否则将出现“unmerged”消息错误。使用-m将“取消 merge ”文件(删除阶段0条目并重新创建冲突的merge2),而--ours--theirs将任何阶段0条目保留在原位置(解决的冲突得以解决)。
  • 在任何情况下,如果仍未出错,请使用位于此处的Blob SHA-1将 repo 副本(或多个副本,如果file_name命名为目录)提取到工作目录中。

  • 因此,简短的版本是“是和否”: git checkout有时会修改索引,有时仅使用它。但是,文件本身从不存储在索引中,而仅存储在存储库中。如果您对文件进行 git add,对其进行更多更改,然后再次对其进行 git add,则将git fsck视为“悬空 Blob ”:没有引用的对象。

    1我故意省略索引中的许多其他内容,以使git表现良好,并允许 --assume-unchanged等。(这些与此处的add/checkout操作无关。)
    2此重新创建会考虑对 merge.conflictstyle所做的任何更改,因此,如果您决定喜欢 diff3输出,并且在没有 diff3样式的情况下已经存在冲突的 merge ,则可以更改git config并使用 git checkout -m来获取具有新样式的新工作目录 merge 。

    关于git - "git add file"和 "git checkout -- file"是对称的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20397024/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com