Git暂存区是如何存储文件的?

10

我想了解Git在将文件移入“暂存”状态时实际存储了什么。

考虑以下序列:

添加并提交新文件至本地代码库:

touch file.txt
git add file.txt
git commit

我对文件进行了更改:

echo text1 > file.txt
git add file.txt

然后我再次编辑文件,然后提交:

echo text2 > file.txt

git status 显示:

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   file.txt
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   file.txt
#

我接着提交了这个文件:

git commit file.txt

Git如何能够在没有被通知的情况下处理新的、第二次更新的file.txt的暂存呢?“状态”输出的结果似乎会尝试检查第一个修订版,但会保留未暂存的更改而不将它们检入。

这种情况下是否存在隐式的暂存操作?


请注意,这个问题的核心实际上有比这里的答案更简单的解决方式。请参考这个问答:https://dev59.com/0IXca4cB1Zd3GeqPMbYi#27264847。 - Petr Bodnár
2个回答

11

把Git看作是两个东西 - 提交(文件的快照)和标签(分支等)。

实际上,当你执行git add时,Git会创建一个提交,而不是当你执行git commit时。所以当你在更改文件后执行git add时,它会创建一个包含这些更改的提交,并将"staging"标签分配给该特定提交。

当你在执行git commit之前再次更改文件时,它现在具有"staged commit"(尚未执行git commit的提交),以及既未添加也未提交的文件的新更改。这就是为什么git status能够同时显示两者的原因。

当你执行git commit时,它实际上是将你当前的分支标签移动到该特定提交(并删除"staging"标签),所以该提交不再标记为"staging",而是标记为"master"(或者你当前所在的任何分支)。


当我运行上述描述的测试时,我观察到的行为是它将文件(“text2”)的未暂存内容提交到仓库中。这个解释正确吗?我认为它应该提交文件(“text1”)的“暂存”版本。我通过执行“git checkout file.txt”确认了这个在仓库中的版本。 - Nick S.
1
我刚刚进行了一项测试,但没有得到你的结果。 mkdir gittest cd gittest git init echo text 1 > test.txt git add . git commit -m 'Initial commit' echo text 2 > test.txt git add . echo text 3 > test.txt 此时,有一个暂存更改(“text 2”)和一个未暂存的更改(“text 3”)。现在,git checkout test.txtcat test.txt。我得到了“text 2”。本地更改被舍弃,使用了暂存更改。 - redhotvengeance
你确定吗?我刚刚完全按照你列出的每个步骤操作,但最终得到的是“text 2”(这是Git的预期行为)。你确定在将文本更改为“text 3”后没有执行git add命令吗?请注意,当您使用git add命令并更改该文件的内容时,当您执行git status命令时,它会显示已暂存的更改和未暂存的更改。此时,如果您执行git add命令,它将使用您所做的新更改更新已暂存的更改。 - redhotvengeance
好的 - 你是对的。我刚刚重新运行了一下,执行了“checkout”之后,文件回到了“text 2”。我以前可能在发出checkout命令时有些错误。感谢你的第二次查看! - Nick S.
2
这不太对,或者可以说它是正确的,但使用了“commit”一词的一种奇特方式。在Git术语中,每个git add的文件都会创建一个新的“blob”,而不是新的“commit”。然后,git commit基于“索引”(又称缓存区或暂存区)编写“树”,如果一切顺利,就会生成一个包含提交消息文本、提交的父级和顶层“树”的“commit”。该“树”可获取“blob”(以及获取更多“blob”的子树等)。 - torek
显示剩余3条评论

4

git commit <somefiles> 相当于先运行 git add <somefiles> 然后再运行 git commit。如果你只运行git commit,则会提交所有已经被暂存的更改,但是不会提交自上次针对该文件暂存以来所做的编辑。


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