以前的"staged but not commited"更改会怎样?

  • 本文关键字:not staged but commited git github
  • 更新时间 :
  • 英文 :


我是git新手,刚开始从这个网站学习:https://dev.to/unseenwizzard/learn-git-concepts-not-commands-4gjc

我的疑问在于文件的这一部分:

看看Alice.txt。
它实际上包含一些文本,但Bob.txt没有,所以让我们更改它并放上嗨!!我叫鲍勃。我是新来的。在那里。

总结一下,我们对Bob.txt进行了更改,改为:-嗨!!我叫鲍勃。我是新来的
we进行了此更改,但没有提交
后来,我们继续对同一句话进行了另一次更改,删除了多余的内容!在嗨之后。

现在的句子是这样的:-嗨!我叫鲍勃。我是新来的
现在我们上演承诺这一新变化。

我的疑问是:之前对Bob.txt的修改(有两个!!)是否从暂存区丢失了?我运行了git status,但它没有提到以前的更改。我可以回去用这两个"quot?

VonC的答案和Romain Valeri对该答案的补充都是正确的,但可能很难以各种方式可视化或理解。这里有一种理解它的方法,它可能至少有点直观。

当您在Git中处理提交时,每个文件最多有三个副本。一旦您知道提交包含每个文件的完整快照(只读(仅限Git,压缩和消除重复)格式,您就会明白为什么有必要拥有两个副本:

Git's read-only copy in HEAD        your working tree copy
----------------------------        ----------------------
file1.ext                           file1.ext
file2.ext                           file2.ext
readme.md                           readme.md

即使commitfile1.ext的内容与工作树中file1.ext的内容匹配(工作树是您查看和处理Git从commit中提取的文件的地方),Git副本也是某种特殊、奇怪、压缩和只读的格式。只有Git本身可以读取这个文件,任何东西——甚至Git本身——都不能覆盖它。1你的工作树包含普通的日常文件,每个人都可以用普通的方式读写,所以每次你检查提交时,Git真的必须将其复制出来。

同样的原则也适用于其他版本控制系统:在Mercurial、SVN、CVS或ClearCase或其他系统中,您经常会发现文件的多个副本(确切的细节在很大程度上取决于VCS)。然而,Git特别奇怪的是,它不是每个文件只有两个副本,而是提供三个:

HEAD (r/o)    staging area    working tree
----------    ------------    ------------
file1.ext     file1.ext       file1.ext
file2.ext     file2.ext       file2.ext
readme.md     readme.md       readme.md

HEAD副本是提交中的,不能更改,所以就是这样。工作树副本是您的,可以随意使用。奇怪的是,这个额外的副本位于HEAD和工作树版本之间。

你不能看到这个额外的版本,至少不容易2但它就在那里。为什么?答案之一是:;"没有理由"--毕竟,那些其他版本控制系统不能做到这一点3但Git确实做到了,Git有一个原因而不仅仅是";不同";。特别是这个";集结区";copy允许您使用git add -p部分添加文件。有一整套这样的局部操作(git reset -pgit checkout -p等),我个人并不是这些操作的超级粉丝,但它们确实存在,并且经常被用作集结区存在的理由。

存储在暂存区中的数据以Git在提交中使用的只读、压缩和消除重复的形式秘密4。这对Git本身的作用是使git commit运行得非常快(无论如何,与所有其他VCSE相比)。运行git commit时,临时区域中的文件副本已准备好提交。几乎不需要额外的工作5当您运行git checkout时,Git会用您签出的提交中的所有文件预填充索引/暂存区域——这是Git中同一事物的两个术语。运行git add时,Git:

  • 压缩并散列工作树文件的内容
  • 检查是否重复;以及
  • 如果是重复的,请重新使用旧的,否则保存新的

这样文件就可以使用了,Git可以用新的或重复使用的内部哈希ID更新其索引条目/暂存副本。6这意味着索引/暂存区域现在可以提交了。

如果我们把这些放在一起,我们会看到以下内容:

  • 完全提交签出(或git switch):填充索引/暂存区域您的工作树:

    HEAD         staging      working tree
    ----         ----------   -------------
    file1.ext -> file1.ext -> file1.ext
    file2.ext -> file2.ext -> file2.ext
    readme.md -> readme.md -> readme.md
    
  • git add:从工作树复制到索引/暂存区。假设我们只是git add file2.ext:

    HEAD         staging      working tree
    ----         ----------   -------------
    file1.ext    file1.ext    file1.ext
    file2.ext    file2.ext <- file2.ext
    readme.md    readme.md    readme.md
    

现在各种其他操作也开始有意义了:

  • git rm --cached:删除索引副本,其他内容保持不变。假设我们git rm --cached file2.ext:

    HEAD         staging      working tree
    ----         ----------   -------------
    file1.ext    file1.ext    file1.ext
    file2.ext                 file2.ext
    readme.md    readme.md    readme.md
    
  • git reset,在其模式之一中:从HEAD副本恢复暂存副本(仅),例如git reset -- file2.ext

    HEAD         staging      working tree
    ----         ----------   -------------
    file1.ext    file1.ext    file1.ext
    file2.ext -> file2.ext    file2.ext
    readme.md    readme.md    readme.md
    
  • 不带--cachedgit rm:删除索引工作树副本:

    HEAD         staging      working tree
    ----         ----------   -------------
    file1.ext    file1.ext    file1.ext
    file2.ext
    readme.md    readme.md    readme.md
    
  • git restore:根据标志恢复暂存、工作树或两者;假设我们现在运行git restore -SW file2.ext来恢复两者:

    HEAD         staging      working tree
    ----         ----------   -------------
    file1.ext    file1.ext    file1.ext
    file2.ext -> file2.ext -> file2.ext
    readme.md    readme.md    readme.md
    

git checkout命令的模式模拟了git restore可以做的两件事:它可以从暂存复制到工作树,也可以从HEAD复制到暂存工作树7这有点危险,因为这些操作会覆盖工作树副本,即使您从未将其保存在任何位置。这使得使用CCD_ 26代替CCD_;"更安全";,因为你不会偶然得到这种破坏性的操作模式8

因此,简短的答案(为时已晚)是,您的第二个git add覆盖了您的第一个git add所写的暂存副本,丢弃了早期的暂存副本。现在很难再回来了。


1从技术上讲,只要文件存储为Git所称的松散对象,就不难读取:用任何zlib解压缩程序打开底层对象并对其进行解压缩,然后丢弃Git添加的头。但仅仅是独自找到这个物体是一件痛苦的事,然后它可能与";松散";,其不是";紧密的";而是打包,然后你真的有麻烦了。

重写文件在物理上是可能的,但因为对象的名称是对象数据的密码校验和,所以重写文件只会损坏数据,以至于Git会说";该对象已损坏";并拒绝提取它。您将知道存储库已损坏,并且应该找到其他未损坏的克隆。

2要不容易看到它,请运行git ls-files --stage;请注意,这会从大型存储库中的输出中转储出来。

3Mercurial,例如,字面上没有,但确实有一个隐藏的东西,叫做";dirstate";这做了Git索引所做的一些。不过,Mercurial的目录状态和Git的索引之间面向用户的区别在于,您甚至不必知道目录状态的存在。Git不时地把它的索引/暂存区推到你脸上:看!我有这个额外的副本!这不是很酷吗?看,看你真的必须意识到这一点。

4使用CCD_;秘密";,所以这并不是所有的秘密。但您不需要知道这一点,除非您自己开始使用git ls-files --stage,和/或将其与git update-index结合使用。

5需要做的一点额外工作是Git必须运行内部等效的git write-tree。这将保存文件的名称和模式数据——文件的内容已经是";预先保存";,正如罗曼·瓦莱里所指出的。

6读者练习:如果你git add一些内容,然后从不提交它,例如,用新内容覆盖它,该怎么办?有一个内部Git对象似乎从未在这里使用过。查看git gc文档,了解最终会发生什么。

7git restore命令可以从HEAD复制到工作树,如果您愿意,可以跳过临时副本;git checkout无法执行此操作。你是否想这样做,我不知道:这取决于你。但是,如果您决定要执行此操作,请记住git restore的功能比git checkout的其他模式更强。

8;"意外破坏模式";在Git2.23及更高版本中,这种情况不再发生,它现在注意到您的git checkout zorg请求是不明确的。这是在旧版本的Git:中发生的地方

  • 假设您有一个名为origin/zorg分支
  • 假设您还有一个名为zorg文件,并且您已经运行了git checkout develop并获得了该文件的develop分支提示副本
  • 现在假设你花了最后一个小时来制定解雇出租车司机的邪恶计划
  • 现在你休息一下喝咖啡(小心不要被樱桃噎住)。当你回来的时候,你会想:等等,我想加入zorg分支所以你运行git checkout zorg

您没有zorg分支,但您有origin/zorg,您希望Git从origin/zorg创建一个新的分支zorg并切换到它(如果安全的话),或者给您一个错误,提醒您隐藏或提交文件。但是,Git说:哦,你想让我删除你在文件zorg上最后一个小时的工作,从而将文件zorg的暂存副本提取到你的工作树中。

如果你使用git switch zorg,Git就会知道你想要创建一个新分支,并且会安全地尝试。但是Git却毁了你的作品。真倒霉只是不要去杀一群人(甚至芒果)来发泄你的沮丧,好吗?😀

之前对Bob.txt的修改(带有两个!!)是否已从暂存区丢失?

是:暂存区用于准备下一次提交
如果更改同一个文件并再次添加,则会修改该暂存区域,下一次提交将不知道您的初始状态。

我可以回去用两个"!提交更改吗">

不能单独使用Git
如果您有一个具有本地历史记录功能的IDE,那么上述IDE可能会有所帮助。

让我们补充一点,当您暂存更改时,git会在数据库中内部创建相应的树和Blob,即使它们在任何提交中都没有被引用。

所以CCD_ 56应该找到你的";分期但未提交";更改为悬挂斑点,您可以使用git cat-file -p <hash>进行检查

所以他们从集结区丢失了,是的,但并非完全无法恢复

最新更新