当前要切换到另一个git commit(在同一分支上...实际上是在master分支上!),我正在执行命令
git checkout ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a
现在,每次执行此操作时,git都会告诉我,我现在头顶分离。我该如何进行较早的提交,并且仍然将头保持在同一分支上?
当前要切换到另一个git commit(在同一分支上...实际上是在master分支上!),我正在执行命令
git checkout ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a
现在,每次执行此操作时,git都会告诉我,我现在头顶分离。我该如何进行较早的提交,并且仍然将头保持在同一分支上?
git checkout
到另一个提交或分支的名称将HEAD移到新的位置)。
git revert --no-commit 0766c053..HEAD
将执行此操作,0766c053
您要检出的提交在哪里。这来自stackoverflow.com/a/21718540/525872。
Answers:
在大多数情况下,我会签出到临时分支:
git checkout -b temp-branch-name ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a
然后,我完成后就删除分支
这取决于签出该提交时要执行的操作。如果您正在做的只是检查它,以便可以构建或测试该修订版,那么使用分离的头没有任何问题。只要记得在进行任何提交之前先检查一个实际的分支(git checkout master
例如),这样就不会创建未包含在任何分支中的提交。
但是,如果您希望从那时开始进行更多提交,则应创建一个分支。如果您进行的提交没有被分支引用,则它们很容易丢失,最终将被git的垃圾收集器清除,因为没有东西引用它们。您可以通过运行以下命令创建一个新分支:
git checkout -b newbranch ea3d5ed
为了帮助可视化,下面是一些图表,它们说明了在分离的头上进行操作与在分支上进行处理有何不同。
让我们从master
,A,B和C上的3个提交开始。master
是当前分支,所以HEAD
指向master
,它指向提交C。
美国广播公司 *-*-* <-主<-头
现在,如果我们提交,git将创建一个以C作为父提交的提交(因为这是当前提交,HEAD
通过via指向master
),并将更新master
以指向该新提交。我们所有的提交现在都在master
,并通过HEAD
指向新的提交master
。
A B C D *-*-*-* <-主<-头
现在,让我们检查一下B,给我们一个独立的HEAD
。
A B C D *-*-*-* <-主 ^ \-头
这里一切正常。我们可以查看所有文件,构建程序,对其进行测试,等等。我们甚至可以创建新的提交。但是,如果这样做,就没有分支,因此我们不能将任何分支指向该新提交。唯一指向它的是HEAD
:
A B C D *-*-*-* <-主 \ * <-头 Ë
如果我们以后决定master
再次签出,将没有任何内容涉及E。
A B C D *-*-*-* <-主<-头 \ * Ë
由于没有任何引用,因此很难找到它,并且git认为没有引用的提交将被放弃(如果您变基,压缩补丁或进行其他有趣的历史操作,则它们很常见;它们通常表示被丢弃的补丁您不再在意的)。在一定时间后,git会将其视为垃圾,在下次运行垃圾收集时将其丢弃。
因此,如果您感觉要进行更多提交,而不是签出裸露的修订版本并得到一个独立的负责人,则应使用git checkout -b branch B
创建一个分支并将其签出。现在,您的提交不会丢失,因为它们将包含在一个分支中,您可以轻松地引用它,并在以后合并。
A B C D *-*-*-* <-主 ^ \-分支<-HEAD
如果您忘记执行此操作,并且在分支上创建了提交,则无需担心。您可以使用来创建引用主要修订版的分支git checkout -b branch
。如果您已经切换回master
分支,并且意识到自己忘记了一个杂项提交,则可以使用来找到它git reflog
,它将向您显示HEAD
过去几天中提交指向的历史。仍然保留在reflog中的所有内容都不会被垃圾回收,通常,引用在reflog中至少保留30天。
HEAD
引用直接指向提交的SHA-1,而不是指向分支,而分支又指向提交。因为您的头没有引用分支,所以Git不知道在添加新提交时要更新哪个分支。正如我在回答开始时所解释的那样,如果您要返回用于构建或测试代码的旧版本,则可以拥有一个独立的头。您总是可以使用git checkout master
或类似符号返回分支。这只是一个问题,如果您在脑袋分离的情况下进行操作。
Git的HEAD只是一个指示工作目录中内容的指针。如果要检出不是分支头的提交,只需要将HEAD重定向到该提交即可。没有办法解决。您可以在该提交处创建一个临时分支,但是HEAD仍将与master分开。
这就是简短的解释。以下详细信息将有助于理解HEAD和master的不同之处:
通常情况如下:
C ← refs/heads/master ← HEAD
↓
B
↓
A
就是说:“ C的父是B,B的父是A。分支master指向C,目前我已检出master的内容。另外,当我提交时,将更新master。”
在此隐含一些假设,这些假设对于全面理解提交图是必需的。即,提交仅引用其父级,分支的内容是可以通过跟随父级链接到达的那些提交(并且仅是那些提交)。工作树(未修改)的内容和索引必须与HEAD命名的提交相对应,无论是间接(“符号”)还是直接(“分离”)。
因此,如果您想签出旧的提交,则必须更新HEAD以指向所需的提交。git-checkout
只是这样做:
C ← refs/heads/master
↓
B ← HEAD
↓
A
现在,由于您正在寻找旧的东西,因此您已经将分支机构抛在了后面。完全可以,“冷静的头脑”建议会冷静地告诉您(强调我的意思):
您可以环顾四周,进行实验性更改并将其提交,也可以放弃在此状态下所做的任何提交,而不会通过执行另一次签帐而影响任何分支。
另一方面,在重置分支的同时也会使HEAD到达需要的位置,但效果会大不相同!
C
↓
B ← refs/heads/master ← HEAD
↓
A
提交C将变为垃圾,因为您已经声明不希望它成为master分支的一部分。
简而言之,您要做的就是了解git对“ HEAD”的含义-它在您所在的位置,而不是任何给定分支的位置。并且,如果您所在的位置与分支所在的位置不同,则别无选择,只能使用分离的HEAD。
(如果您的HEAD出轨仍然让您感到烦恼,也许还可以查看GitHub,gitk或gitweb来浏览提交历史记录。)
这个问题有点含糊,但是如果您只想更改工作树中的文件,则只需执行以下操作:
git checkout [commit|branch] -- .
然后,您可以进行更改并根据需要创建新的提交。有时候这很有用。