签出旧的提交并保持主分支的头部?

时间:2011-04-14 03:47:02

标签: git version-control

目前切换到另一个git提交(在同一个分支上......实际上,在主分支上!),我正在执行命令

git checkout ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

现在,每次我这样做时,git告诉我,我现在有一个超然的头。我如何进行较早的提交仍然保持在同一分支上?

6 个答案:

答案 0 :(得分:188)

大多数时候,当我这样做时,我会结账到临时分支:

git checkout -b temp-branch-name ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

然后,在我完成后,我只删除分支

答案 1 :(得分:78)

这取决于您在签出提交时要执行的操作。如果您所做的只是检查它以便您可以构建或测试该修订版,那么使用分离的头部没有任何问题。只需记住在进行任何提交之前检查一个实际的分支(例如git checkout master),这样就不会创建任何分支中未包含的提交。

但是,如果您想从该点开始提交更多提交,则应创建一个分支。如果你做了一个没有被分支引用的提交,它们很容易丢失,最终会被git的垃圾收集器清理掉,因为没有任何东西引用它们。您可以通过运行:

来创建新分支
git checkout -b newbranch ea3d5ed

为了帮助实现可视化,这里有一些图表,展示了在分离头上工作与在分支上工作的不同。

让我们从master,A,B和C开始提交3次。master是当前分支,因此HEAD指向master,指向HEAD提交C.

A  B  C
*--*--* <-- master <-- HEAD

现在,如果我们提交,git将创建一个将C作为父级的提交(因为这是当前提交,从master通过master指向),并将更新master指向新提交。我们的所有提交现在都在HEADmaster通过HEAD指向新提交。

A  B  C  D
*--*--*--* <-- master <-- HEAD

现在让我们看看B,给我们一个分离的HEAD

A  B  C  D
*--*--*--* <-- master
   ^
    \-- HEAD

这里的一切都很好;我们可以查看所有文件,构建我们的程序,测试它等等。我们甚至可以创建新的提交;但是如果我们这样做,那么我们就没有分支,所以我们不能指出任何分支在新的提交。唯一指向它的是master

A  B  C  D
*--*--*--* <-- master
    \
     * <-- HEAD
     E

如果我们以后决定再次查看git checkout -b branch B,则没有任何内容涉及E.

A  B  C  D
*--*--*--* <-- master <-- HEAD
    \
     *
     E

由于没有任何内容可以引用它,因此很难找到,并且git会认为没有引用的提交会被放弃(如果您进行修改,或者将补丁压缩,或者进行其他有趣的历史操作,它们会发生很常见;它们通常代表你不再关心的废弃补丁。经过一段时间后,git会认为它是垃圾,下次垃圾收集运行时会被丢弃。

因此,如果您觉得要进行更多提交,则应该使用git checkout -b branch来创建分支并检查它,而不是检查一个简单的修订版并获得一个独立的头部。现在你的提交不会丢失,因为它们将被包含在一个分支中,你可以很容易地引用它,并在以后合并。

A  B  C  D
*--*--*--* <-- master
   ^
    \-- branch <-- HEAD

如果您忘记这样做,并在分支机构上创建提交,则无需担心。您可以使用master创建引用头部修订的分支。如果您已经切换回HEAD分支,并意识到您忘记了一个迷路提交,则可以使用git reflog找到它,它会显示提交{{1}}的提交历史记录在过去几天指出。仍然存在于reflog中的任何东西都不会被垃圾收集,并且通常引用会在reflog中保存至少30天。

答案 2 :(得分:7)

如果您只想返回之前的提交以进行播放而不进行任何更改,则可以执行

git co <previous-commit-id>

在此命令之后,您将在一个名为“(无分支)”的分支上。

通过

确认
git br

使用此前提交的代码后,您可以切换到您所在的分支

git co <the-branch-you-were-on>

“(无分支)”将自动删除。这样您就不需要创建临时分支。

答案 3 :(得分:5)

Git的HEAD只是一个指针,指出工作目录中的内容。如果要查看不是分支头的提交,只需将HEAD重定向到指向该提交即可。没有办法绕过它。您可以在该提交中创建一个临时分支,但HEAD将被引导远离master。

这是简短的解释。下面的冗长将有助于理解HEAD和主人是如何不同的:

通常情况如下:

C ← refs/heads/master ← HEAD 
↓
B
↓
A

这就是说:“C的父级是B,B的父级是A.分支主控指向C,我目前已经检查了master的内容。另外,当我提交时,主人应该更新。“

这里隐含了一些假设,这些假设对于彻底理解提交图是必需的。也就是说,提交只引用它们的父项,而分支的内容是那些可以通过跟随父链接到达的提交(并且只有那些提交)。工作树和索引的(未修改的)内容必须对应于HEAD命名的提交,间接(“符号”)或直接(“分离”)。

因此,如果要检出旧提交,则必须更新HEAD以指向所需的提交。 git-checkout就是这样做的:

C ← refs/heads/master 
↓
B ← HEAD
↓
A

现在,你已经离开了你的分支,因为你正在寻找旧的东西。这是完全可以的,因为“独立的头”建议平静地告诉你(强调我的):

  

您可以环顾四周,进行实验性更改并提交它们,并且您可以通过执行其他结帐来放弃您在此状态下执行的任何提交而不影响任何分支

另一方面,虽然重置你的分支也会得到它需要的HEAD,但它会产生非常不同的效果!

C
↓
B ← refs/heads/master ← HEAD
↓
A

提交C将变为垃圾,因为您已声明不再希望它成为主分支的一部分。

简而言之,您所要做的就是通过“HEAD”了解git的含义 - 它就是所在的位置,而不是任何给定分支的位置。如果所在的地方与分支的位置不同,那么除了使用分离的HEAD之外别无选择。

(也许还会查看GitHub,gitk或gitweb以浏览提交历史记录,如果您的HEAD出轨仍然让您感到厌烦。)

答案 4 :(得分:1)

问题有点模糊,但如果你只想更改工作树中的文件,你可以这样做:

git checkout [commit|branch] -- .

然后,您可以根据需要暂存更改并创建新提交。这有时非常有用。

答案 5 :(得分:0)

我想我理解你的问题。这是我发现解决它的问题。并且没有它的GUI解决方案,你只能使用命令来解决它,而且它非常简单。

步骤1:创建您想要返回的旧提交的标记。

喜欢标签v2.0

第2步:git checkout v2.0

现在它是,现在你的HEAD指向'v2.0'提交,但是master仍然指向最后一次提交。

C:\Program Files\Git\doc\git\html\git-checkout.html本文档可能会对您有所帮助

或输入git help&lt;结帐&gt;

相关问题