Git:签出如何影响存储库?

时间:2015-09-28 23:52:24

标签: git

我对编程没有任何经验,我只是开始学习Git。我不明白git checkout是如何运作的。

根据this

  

签出旧提交是一种只读操作。在查看旧版本时,不可能损坏您的存储库。项目的“当前”状态在主分支中保持不变。

下面的段落,他们说明了这一点:

  

另一方面,签出旧文件确实会影响存储库的当前状态。

对我而言似乎是完全矛盾的。有人可以用外行的话来解释这个吗?

4 个答案:

答案 0 :(得分:4)

第二句最好写成:

  

签出旧文件确实会影响工作区的当前状态

如果您将存储库视为整个项目历史记录中所有文件版本的历史记录,则工作区是某些州的文件快照。

checkout将内容从存储库移动到工作区中。它只从存储库中读取,但它写入工作空间。因此,它无法更改仓库,但它可以更改您的工作区。

答案 1 :(得分:0)

因为第一段解释了

git checkout <some commit>

和第二段解释

git checkout <some file>

它们具有不同的语义,特别是第一个是只读的,而第二个确实改变了存储库的状态。

答案 2 :(得分:0)

想象一下,你是在你的主分支,这是你完美的现状。

git checkout master

想象一下,你只是想进入特定的状态或看看你做某些提交时的情况,想象提交的名称是97b4b6c。如果你之前做过97b4b6c提交,git提供了一个选项你可以进入那个状态并检查存储库。

  

记住git checkout ~97b4b6c进入97b4b6c提交状态。   进入这种状态,你的当前状态(主)将不会   伤害。您可以随时返回当前状态(主)。这个   就像,你可以在A(主)和B(97b4b6c)状态之间切换,这个   切换不会影响A或B.

   .             .
A (master)    B (97b4b6c)

git checkout ~97b4b6c #commit name

如果您只对单个文件感兴趣,还可以使用git checkout来获取旧版本的文件。例如,如果您只想查看旧提交中的hello.py文件,则可以使用以下命令:

git checkout commit hello.py

以同样的方式,如果你想在主状态下看到hello.py,在97b4b6c中看到hello.py。

           .             .
hello.py-A (master)    hello.py-B (97b4b6c)

git checkout 97b4b6c hello.py

将在97b46c提交状态下显示hello.py文件。以同样的方式,您也可以通过执行以下操作来查看处于主状态的同一文件:

git checkout master hello.py

请记住,与签出提交不同,这会影响项目的当前状态。旧文件修订版将显示为“要提交的更改”,使您有机会恢复到该文件的先前版本。如果您决定不想保留旧版本,可以使用以下内容查看最新版本。

<强>要点:

git check <commit>

将带您进入特定的提交状态,

git checkout <some file>
  

然而,git checkout和git之间的重要区别   结帐是,git checkout <commit>不会影响   您项目的当前状态,但git checkout <some file>会   肯定会影响你当前的项目状态

还会将您带到特定文件的旧版本

所以,git checkout是一个基本上把你带到某个状态的命令。它是通过提交名称或文件名来执行的。

答案 3 :(得分:0)

Git的文档肯定会有所不足。

上面的一个答案点击了一个关键点,即如果你要求git checkout从特定版本获取特定文件,这会产生比你预期更大的影响

背景

您需要知道的是,在检出文件时,有三个感兴趣的事情:

  • 存储库本身
  • 你的工作树
  • git调用&#34;索引&#34;或者&#34;临时区域&#34;

第四项,即当前分支,git checkout也会影响,但这一部分最初是显而易见的。最终它以通常的git方式变得不那么清晰了。 :-)我稍后会谈到这一点。

在使用git checkout到&#34时,请及时回顾&#34;对于早期的提交,相当清楚这会影响您的工作树。除非git实际上提取了README.txt的早期版本,否则无法查看早期版本的README.txt。因此,当然git checkout会影响工作树。

然而,存储库本身 - 每个已提交文件的每个版本的集合,加上所有提交本身 - 实际上都不受影响,所以说存储库<是合理的/ em>在这里是只读的。 (实际上,更改内容的操作,添加新提交,大多数只是添加到存储库。一旦事情是git commit,很难让git忘记任何事情 - ed。甚至出现以删除事物的操作,例如在交互式rebase期间删除提交,实际上只是添加的东西。但这又是另一次。)< / p>

使用git checkout

现在,这就是它有点松散的地方:在我看来,git checkout实际上是两到五个相当不同(虽然相关)的命令,都被压缩成一个git checkout命令。确切的数字取决于你想要将它们分开的清晰度(我说它们至少应该分成两部分,我自己):

  1. 查看特定分支,例如git checkout mastergit checkout feature
  2. 查看旧提交,以便您根本不在分支上:git checkout afe3ca9,或git checkout v1.2 v1.2是标记。
  3. 从工作树中提取从当前索引中获取的文件(或许可能是很多文件)(我稍后会对此进行说明):例如git checkout -- fromindex.txt。仅当文件的名称可能类似于有效的修订版ID时才需要--,但总是要包含它是一个好主意,以免您意外使用您认为的内容是安全的,但结果是映射到有效的版本ID。
  4. 从工作树中提取旧提交中的文件(或许多文件),但不要移动当前提交:git checkout master~20 README.txt
  5. 重新创建合并冲突,或通过选择特定版本来解决合并冲突:git checkout -m recreate.pygit checkout HEAD file.c。 (请注意,最后一个看起来与命令#4相同。这里的关键区别在于命令#4仅在您处于冲突合并的中间时适用,并且由于这种方式而存在合并使用索引。我们稍后会对此有更多的了解。)
  6. 这些命令中的每一个都有不同的效果。

    分支机构结账会让您“#34; on&#34;该分支,删除和/或替换到达那里所需的任何工作树文件。这种结账非常小心,不要破坏您在工作树中所做的任何修改,如果您丢失了一些工作,它会给您一个错误(此时您可以先保存该工作,然后使用force标志,例如)。

    历史结帐非常类似于分支结帐。如果您git checkout v1.2,为了查看标记为版本1.2的提交中的内容,git会执行与更改分支相同的安全检查。关键的区别在于,如果一切顺利,git会为您提交标记为v1.2的提交,并且您不再在任何分支上。你有什么git称为&#34;分离的HEAD&#34;。 (您可以&#34;分离您的头部&#34;即使在检查分支时,也可以添加--detach。很少有理由这样做,还有其他方法可以做到这一点,所以--detach标志实际上是完全没必要的,但这完全是另一个问题。)

    这两种git checkout都会将您从一个提交(和/或分支)转移到另一个提交(不同的提交)。他们更新工作树,并改变git对当前分支/提交的想法。

    我之前提到&#34;当前分支&#34;仔细观察时会有点朦胧。这是因为&#34;分离的HEAD&#34;事情。为了记录您当前的分支,git将分支名称写入文件.git/HEAD。您可以使用文件查看器或编辑器查看此文件(但请注意不要删除它,就像它已经消失一样,git将不再相信您有一个存储库!)。通常,此文件包含ref: refs/heads/masterref: refs/heads/branch,而 知道您正在使用哪个分支。但是该文件还可以包含一个原始SHA-1,这是一个非常丑陋的40个字符的ID,它们是&#34;真正的名字&#34;提交。这是你有一个&#34;分离的HEAD&#34;,在这种情况下,SHA-1是你当前的提交。 (当您在分支机构上时,当前的提交ID保存在分支机构的文件中:.git/refs/heads/master,但有时这些参考文件被打包并且#34;以节省空间和时间。)

    现在让我们回到结帐命令类型#3到#5。这些检查您是否在工作树中删除某些内容,因为他们更改您当前的提交ID,也不会影响您当前的分支。相反,它们使用所选提交中的所选文件的内容覆盖您的工作树,或者,为了重新创建合并,重新尝试合并的结果是您在中间的。但他们又做了一件非常重要的事情:他们写入索引。 (或者,您可能希望将此视为将通过索引写入工作树。)

    为什么这很重要?

    为什么索引很重要

    Git使用索引来构建 next 提交,即尚未创建的提交,但是当您运行git commit时。这就是为什么它也称为&#34;暂存区域&#34;:它是您安排文件的地方,然后一旦按照您想要的方式排列所有内容,您只需运行{ {1}}将暂存区域快照到存储库中,进行新的提交。

    这意味着,如果您在分支git commit上,并且您的工作树和索引都是干净的,那么您决定查看较早版本的{{1 }}:

    master

    然后git不仅更新了您的工作树,而且修改了您当前的索引,因此,如果您执行新的README.txt,那么您就可以了放回旧的$ git checkout master $ git checkout master~20 README.txt 文件。

    您可以轻松切换索引版本:

    git commit

    但你需要记住这样做。 (您也可以使用README.txt执行此操作,但请注意,$ git checkout master README.txt git reset一样,是几个命令都被压缩为一个。)

    关于合并的简短说明

    我提到合并使用索引。如果您处于冲突合并的中间,git会在索引中保留每个冲突文件的三个 1 版本,这些版本通常称为&#34; merge-base&#34;,& #34;我们的&#34;,&#34;他们的&#34;,但也被计算在内:1,2和3.到&#34;解决&#34;合并,你告诉git用&#34;版本0&#34;替换这三个。当您使用git reset添加已解决的合并时,这就是您正在做的事情;但您也可以使用git checkout解析合并,该git add写入版本号为零,以便解决版本1-3。

    运行git checkout时,此checkout变体将删除版本0并重新创建版本1-3。你不需要正常地了解所有这些,但它可以在合并过程中从错误中恢复。

    1 由于合并可以运行到文件删除或文件创建的操作中,因此实际上最多三个版本。如果该文件不存在于合并库中但存在于两个合并更改中,那么您将在&#34; merge-base&#34;中出现冲突。插槽中的插槽。