0

我对 Git 还很陌生——自从我开始为现在的雇主工作以来,我才开始使用它。

我最近向服务器推送了一些更改,合并了一个同事在我的本地开发机器上实现的错误修复。我通过branch从服务器上提取他们已经实施了错误修复的他们来做到这一点,并将其与我的本地master分支合并,该分支与代码的实时版本是最新的。我在本地开发机器上对此进行了测试,似乎一切正常,因此我将其推送到服务器。

然而,我所做的更改似乎在实时版本中引入了另一个错误(它引入的错误在本地测试修复时并不明显,只有在代码上线后才会出现)。

我引入的这个错误实际上导致内部公司网站的大量使用部分无法访问,因此我立即检查了最后一次工作commit并重新启动服务器,以便再次访问该站点。

我现在正在解决修复程序在我的本地开发机器上引起的问题,然后再次将修复程序推送到服务器,但是在服务器上检查了一个旧commit版本后,项目的实时版本处于一种detached HEAD状态。它当前所处的detached HEAD状态主要是功能性的(即它的工作方式与我的同事开始修复此错误之前的工作方式相同 - 因此错误仍然存​​在)。

我现在想解决detached HEAD服务器上的问题,以便我可以再次从服务器中提取工作代码,从这一点重新开始,但我不确定我如何将其余代码与detached HEAD我的代码“匹配”我目前正在工作。

如果我git branch在服务器上运行,输出显示我只有master分支(它已损坏 - 因为它有我在推送原始错误修复时引入的错误)​​,并且是当前指向(detached from 0e57d3d)的那个。HEAD

我看过的其他帖子似乎表明我应该结帐master以解决问题detached HEAD,但我不能这样做,因为我知道master目前已损坏。

那么我怎样才能“附加”HEAD又一次,以便代码在它所指向commit的状态下工作呢?HEAD我可以从那里运行一个git branch,然后检查它branch,然后让它成为master吗?还是有其他方法可以做到这一点?

4

1 回答 1

1

乍一看,这看起来像是Fix a Git detached head? 它在某些方面是,而不是在其他方面。此外,正如 Thorbjørn Ravn Andersen 在各种评论中所说,您可能还想与其他同事进行协调。但是,让我们做一些不在(并且实际上不适合)其他问题的注释。

一个分离的 HEAD 不会改变任何东西——反正现在还没有

首先,“分离的 HEAD”仅仅意味着你已经签出了一个特定的提交,通常是通过它的哈希 ID。this 和 之间只有一个功能差异,因为它还检查了一个特定的提交,这听起来像是一个循环定义,因为它:不同之处在于,当你这样做时,你在一个分支上,而当你这样做时这个,你不在一个分支上,也就是说,你有一个分离的 HEAD。git checkout branch-name

因此,所有“分离的 HEAD”意味着“不在分支上”。也就是说,如果您签出一个特定的提交进入一个分支,那么您就是“在一个分支上”,正如git status将要说的那样;但是,如果您签出相同的特定提交并且没有进入分支,那么您将有一个“分离的 HEAD”,正如git status将要说的那样。

git checkout是您上或下分支的方式

只有一个面向用户的 Git 命令可以进入任何特定的分支,或者分离你的 HEAD 以离开一个分支,那就是git checkout. 如果您git checkout是一个分支名称,它会检查该提交并将您置于分支上。如果你git checkout有其他任何东西——包括标签、远程跟踪分支或原始哈希 ID——它会给你一个分离的 HEAD。因此,就像在其他问题的已接受答案中一样,如果您只想回到 branch master,您只需git checkout master.

你跑了git checkout 1234567或类似的,检查一个较旧的提交,现在有一个“分离的 HEAD”。

git checkout也会更新您的索引和/或工作树

(这里非常简短的提醒:工作树是 Git 写入和读回的地方,您最终将作为提交永久保存在存储库中的内容的副本。它采用计算机系统的其余部分可以理解的形式,而不是 Git-特定的形式。索引是你和 Git 构建下一次提交的地方;它是非常特定于 Git 的形式,并且有一些额外的 goop 可以在特定于 Git 的内部形式和“正常计算机使用”形式之间进行协调。提交实际上是保存的索引,减去额外的 goop。)

显然,您的服务器正在运行工作树 - 而您首先运行的原因git checkout 1234567是因为分支的尖端提交master,即 1234567 以外的某个提交,不起作用。如果您git checkout master要通过恢复提示提交来重新破坏服务器。

这是您需要与他人协调的地方,因为要重新连接您的 HEAD,您现在必须至少执行以下两项操作:

  • 创建一个分支,或
  • 至少暂时重新破坏服务器。

要创建新分支,请使用git checkout -b newbranch

如果您想并且被允许让服务器“在一个分支上”而不更改提交,只需创建一个新分支,其尖端是当前提交。为此,请使用git checkout -b

git checkout -b mostly-working

mostly-working现在您的 HEAD 已附加到您刚刚创建的分支上。索引和工作树没有任何反应,因为新的分支mostly-working 名称提交 1234567(或您之前签出的任何一个)。

这个提交可能在后面的某个地方mastergit checkout -b也就是说,如果我们要绘制提交图的一部分,在我们做这件事之前,它看起来像这样:

...--o--o--*--o--o   <-- master
           ^
     commit 1234567
          HEAD

所做git checkout -b的只是添加一个指向同一个提交的新名称。为了用纯文本绘制它,我们需要向上或向下推动一些提交(我会选择向上):

             o--o   <-- master
            /
...--o--o--*   <-- mostly-working (HEAD)
           ^
  still commit 1234567

由于我们没有移动commits,索引和工作树保持不变。

如果您现在进行新的提交,他们会推进分支

为了完成上述内容,让我们看看如果您修改工作树中的某些内容会发生什么git add, 和git commit。Git 将在新分支上进行新的提交mostly-working

             o--o   <-- master
            /
...--o--o--o--*   <-- mostly-working (HEAD)

(顺便说一句,我在*这里使用标记当前提交,git branch标记当前分支)。

分离的 HEAD 也会发生同样的事情

假设您没有执行git checkout -b,但确实修改了文件并提交。这将像往常一样进行新的提交——但不是在分支上,新的提交将是新的分离的 HEAD。也就是说,我们将像这样绘制新的提交:

             o--o   <-- master
            /
...--o--o--o--*   <-- HEAD

那么,这就是“在分支上”和“分离的 HEAD”之间区别。“在一个分支上”并没有什么特别之处,只是新的提交在提交时会推进那个分支。分支名称指向分支的尖端。当您git checkout创建分支时,您会检查该分支的最尖端提交。当您进行新的提交时,您可以将它们添加到分支中,方法是将名称指向新的提交。(新的提交本身指向前一个HEAD提交。)因为HEAD只是说哪个分支是当前的,更新分支名称以指向新的提交也会更新HEAD以指向新的提交。

当你有一个分离的 HEAD 时,过程完全一样:新的提交指向前一个提交,新的提交成为新的HEAD提交。这个提交没有名字HEAD(当然,除了,但是HEAD当你改变时git checkout!)。

于 2017-01-25T17:50:57.657 回答