删除一个头部脱落的分支-我会失去头部吗?

时间:2018-08-23 09:41:11

标签: git

我有一个非常混乱的分支,在master后面有很多版本,我拉进去,只想删除它。

我一直在处理此分支的分离头,如果删除该分支,我会失去分离的头吗?

2 个答案:

答案 0 :(得分:3)

Git会重载“ head”一词,这可能会使您误入歧途。不过,公平地说,Git也严重地重载了“ branch”一词。为了使它们保持直线,我们在这里使用短语分支名称

HEAD一词(用大写形式完全像这样拼写,​​ 1 )表示当前提交当前分支名称。好吧,更准确地说,它总是表示当前提交,并且附加时,它表示当前分支名称。

为此,Git通常(通常是 )将分支的名称存储在其HEAD中。然后分支名称标识提交!因此,HEAD拥有分支的名称,而分支名称则拥有提交哈希ID。


1 在Windows和MacOS上,您也可以使用小写字母,这让人感到困惑,但这是当您要求Windows或MacOS打开文件{{ 1}},并且存在一个名为readme的文件,它们将打开大写命名的文件。 Git将您对README的想法存储在名为HEAD的文件中。如果愿意,请查看文件:例如HEAD。它总是只包含一行,通常一行是cat .git/HEAD


绘图分支

实际上,提交哈希ID对于使用分支本身非常重要!我认为这有助于绘制。假设您从一个只有三个提交的微小存储库开始。它们都有一些大的丑陋的哈希ID,对于每个提交都是唯一的,但是为了使其易于管理,我们就称它们为ref: refs/heads/<name>AB,其中C是您进行的第一次提交,A是第二次提交,B是第三次提交。

现在,每个提交都在其只读的,永久保存的数据中记住在之前的提交的哈希ID。由于C first 提交,因此它之前没有任何内容,因此它是独立存在的。由于AB之后,因此A会记住B的ID:我们说A 指向 {{1} }。同样,B记住,即指向A

C

Git现在需要知道的是提交B的哈希ID,即提交链的 end 。这就是分支名称的来源。让我们使用名称A <-B <-C 指向提交C,方法是将master的实际哈希ID存储在名称{ {1}}。并且由于一瞬间就会变得显而易见的原因,让我们这样绘制提交:

C

现在,在不更改存储库中的 commits 集合的情况下,让我们附加另一个分支名称C来提交master而不是 C <-- master / B / A

dev

Git如何知道哪个提交当前提交哪个分支名称是当前分支 ?这就是B的来源。让我们在其中绘制名称C,并将其附加到分支 C <-- master / B <-- dev / A

HEAD

在附加HEAD或分支如何工作的同时进行新提交

现在让我们看看分支在Git中实际如何工作的秘密。使用相同的提交顺序,并在HEAD上附加dev,我们进行一次 new 提交。与所有提交一样,Git将保存所有文件的快照,并为该新快照提供新的,唯一的,大的丑陋哈希ID,但我们将其称为 C <-- master / B <-- dev (HEAD) / A

新提交HEAD必须记住当前提交。我们如何找到当前提交?是的,没错:我们看看dev!它附加到D,并且D指向HEAD,因此dev是当前提交。这意味着我们的新提交dev必须指向B

B

而且,现在我们有了新的提交D作为开发分支的 tip ,Git只需将B的哈希ID写入 name < / em> C / B--D / A 。但是Git如何知道使用名称D?如果您说: Git看着D ,恭喜,您已经了解了附件dev的工作原理!让我们把标签放回去:

dev

请注意,只要我们记得,我们就可以按照自己喜欢的方式绘制此图形:

  • Git可以向后工作。它从附加的HEAD开始以获取分支名称,然后从分支名称中,Git查找分支的 tip 提交。

  • 每个提交点向后指向其父级。 Git跟随向后链接到链中的下一个(上一个?)提交。

  • 当我们厌倦了后续操作,或者达到了无法再进一步执行的提交时,动作将停止:commit HEAD root 提交。

所以:

    C   <-- master
   /
  B--D   <-- dev (HEAD)
 /
A

或:

HEAD

是绘制此图的所有有效方法。 分支名称AA--B--C <-- master \ D <-- dev (HEAD) 标识 tip 提交,然后Git在其余提交中向后工作。

请注意,提交 C <-- master / A--B \ D <-- dev (HEAD) master两个分支上。最后一张图纸使这一点非常清晰,因此有时是要走的路。同样清楚的是,如果我们添加一个新名称(如dev,该名称指向提交B,就像A

m2

现在,提交C位于两个分支master C <-- master, m2 / A--B \ D <-- dev (HEAD) 上。我们可以安全地删除两个名称之一,因为我们仍然可以使用另一个名称来查找提交A-B-C

一个独立的头

因此,如果您的HEAD通常是附加到分支名称-文件master包含分支的名称-分离的HEAD到底是什么?结果也很简单。当文件m2包含原始的 commit哈希ID 而不是分支名称时,将发生分离的HEAD。让我们再次使用最后一个图形绘制,但是现在从C中分离.git/HEAD并使.git/HEAD本身指向直接提交HEAD

dev

现在,从这里开始,通过修改某些文件以及HEADB的常用方法,添加一个 new 提交。 Git将使用新的大的丑陋哈希ID进行新的提交,但我们将其称为 C <-- master / A--B <-- HEAD \ D <-- dev 。提交git add将照常指向git commit ...然后Git将E的哈希ID写入E而不是某个分支名称中,从而得到:

B

提交很重要;名称就是Git查找提交的方式

假设您已完成上述操作,分离的E指向HEAD。现在,假设您删除分支名称 C <-- master / A--B--E <-- HEAD \ D <-- dev

HEAD

提交E会发生什么?从某种意义上说,它仍然存在,但是现在没有明显的方法找到。让我们放回dev,这次,让我们重新附加 C <-- master / A--B--E <-- HEAD \ D ???

D

提交dev会发生什么?同样,它仍然是那里,但是没有明显的方法来找到。因此,在之前我们将HEAD重新附加到 C <-- master / A--B--E ??? \ D <-- dev (HEAD) E,让我们指定一些分支名称来提交{{1} }。也就是说,让我们回到:

HEAD

并运行devmaster。这些操作是创建一个新名称 E,指向当前提交

     C   <-- master
    /
A--B--E   <-- HEAD
    \
     D   <-- dev

或:

git branch temp

这两者之间的区别在于git checkout -b temp是否已附加。使用temp可以创建新名称,而无需附加 C <-- master / A--B--E <-- temp, HEAD \ D <-- dev 。使用 C <-- master / A--B--E <-- temp (HEAD) \ D <-- dev 来命名新名称,并在上附加HEAD

摘要

就是这样-真的很简单! 分支名称指向提示提交,git branch记住分支名称之一。或者,如果您有一个分离的HEAD,HEAD会直接记住其中一个提交。

提交 无关紧要,但是Git使用名称作为起点(或终点?)来找到它们。自动添加 new 提交 会更新当前分支 name ,以指向该分支的新最终提交。或更确切地说,如果将git checkout -b附加到分支,就可以做到!您可以并且应该期望分支名称以这种方式前进。

这里没有介绍,但是很重要:例如某些提交没有 no 名称-例如,因为我们是在独立的目录上找不到提交HEAD,在将HEAD重新连接到其他地方之前,HEAD从来没有为其指定一个名称-提交很容易受到Git的垃圾收集器 HEAD的攻击。自从您上次能够通过HEAD看到提交以来,提交至少通常在30天内不受此类收集的保护,但是,如果没有明显的名称,它们将变得很难找到。但是,这个严峻的 Reaper 收集器HEAD通常会在一个月左右后删除不必要的提交。例如,这就是E的工作方式:git gc 复制提交,然后通过移动分支名称 la HEAD —放弃原始提交,转而使用更新,更明亮的副本。

答案 1 :(得分:1)

否,HEAD不能“丢失”。只需签出其他任何内容,即可获得HEAD所在的指针的全新目标。


关于最近的提交:

就像Tim在评论中提到的那样,您可以从reflog中找回它们。

但是,如果不确定丢失这些提交并希望以某种方式保留它们,请创建一个备份分支,分离的HEAD当前指向该分支。

# let's create a memory of your currently detached HEAD
git checkout -b sleepyHollow

然后继续在您的master上继续工作,如果您需要上一个凌乱的分支进行特定提交,只需将其樱桃拾取回master中,以免合并/减轻困难。备份分支的存在将保留垃圾收集器中的“丢失”提交。