首页 > 解决方案 > 修复或撤消标签上的分离头

问题描述

嘿,我真的可以在这里使用一些帮助来解决我的情况,

我创建了一个空仓库并为其添加了一个标签,并指出 Zenodo 中的仓库用于创建 doi 稍后我将某些文件推送到仓库我真的不知道我是如何搞砸的,但我想我可能已经将标签合并到 main 和当我克隆它时,我不再拥有该标签,我收到的第一条消息是

git clone --depth 1 --branch v1.0 repourl
Unpacking objects: 100% (3/3), done.
Note: checking out 'xxx'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
  git checkout -b <new-branch-name>

有没有办法可以解决这个问题,对我来说在标签中有文件真的很重要,我可以在线看到标签,zenodo 唯一的问题是那里没有文件,但是可以在主分支中找到它们。由于我无法更改zenodo链接,有什么办法可以解决这个问题吗?

标签: gitgithub

解决方案


TL;博士

这里没有什么可以解决的,至少在你问的问题上。

长(ish)

您发布的输出不包含任何错误或错误。但是,您的问题充满了不正确的假设和陈述。众所周知,Git 对于初学者来说很难(或对初学者不友好),而且你已经了解了它的几个经典项目。

第一:文件不存储在标签中。事实上,Git 一开始并不存储文件。Git 存储的是commits。Git 存储库在很大程度上只是大量提交的集合。所以这应该立即给你留下一个问题:究竟什么是提交?

有些细节还不重要,所以我们将跳过它们。最重要的两个是:

  • 每个提交都有编号。然而,这些数字并不是简单的计数数字:它们不是“提交#1”,然后是“提交#2”,然后是#3,依此类推。取而代之的是,每个数字都是唯一的,但又巨大又随机。它以十六进制表示,看起来像d486ca60a51c9cb1fe068803c3f540724e95e83a. 这个数字是 Git 在存储库中实际找到提交的方式。但人类通常不会直接处理数字:它们太大太丑,无法正确输入。

  • 每个提交都包含每个文件的完整快照。这就是 Git 保存文件的方式,即使它不将它们存储文件。Git 存储提交,然后提交将文件存储为一种存档,例如 tarball 或 zip 存档或 RAR 或其他。

为了在存储库中找到提交,Git 给了我们几种名称。最重要的两个是分支名称标签名称两种名称都只存储一个原始提交哈希 ID。 这意味着当您使用该名称时,您将获得该特定提交。在这里,分支名称和标签名称之间的主要区别在于分支名称在不同时间选择不同的提交。更准确地说,分支名称命名了该分支“上”的最新提交。稍后提交,分支名称将——<em>必须——改变。但是,标签名称会永远命名一个特定的提交。

考虑到这一点:

我创建了一个空仓库

到目前为止,一切正常。空存储库是其中没有提交的存储库。由于它没有提交,因此它不能有任何分支或标签名称:分支或标签名称必须包含该存储库中存在的某个提交的哈希 ID。1

请注意,当 GitHub 为您创建新存储库时,他们将(可选)将一个初始提交放入新存储库,以便分支和标签名称可以存在。这会在 GitHub 上创建初始分支名称——过去是,master但现在是。main

并为其添加了一个标签

这部分是不可能的。必须至少有一次提交。

后来我将某些文件推送到了仓库

您所做的是创建一个或多个提交。这允许分支和标签名称出现。然后,您为其中一个提交创建了一个标签名称。您添加的每个提交也包含一些文件集,作为这些特定文件的特定版本的永久存档。

您现在拥有并且可能仍然拥有一个存储库,其中包含一些分支名称(例如master和/或main)以及至少一个标签名称,特别是v1.0. 您还曾经git push将新提交、任何分支名称更新以及新分支和标签名称发送到 GitHub 上的存储库副本。这些是存储库的单独副本,因此它们可能会不同步,而且——这部分非常重要——每个副本都有自己的分支名称。这两个副本共享标签名称和共享提交,但它们每个都有自己的分支名称

...我想我可能已经将标签合并到 main

Gitgit merge是另一个相当复杂的主题,但您不必担心这里的标签。合并操作合并提交。标签,一旦制作,就留在原地。2

当我克隆 [存储库,Git 说]

... You are in 'detached HEAD' state ...

这是因为您告诉git clone您要使用的名称是v1.0

git clone ... --branch v1.0 ...

工作方式git clone是:

  1. 它创建一个新的空目录。3 然后新目录中完成剩余的操作。
  2. 它创建一个新的空存储库(通过运行git init, 实际上)。
  3. 它向这个存储库添加了一个遥控器(或多或少)。这是一个短名称,您的 Git 可以通过它联系另一个 Git,您将要从中复制所有提交。git remote add origin url
  4. 它会运行您要求它执行的任何其他git config操作(您没有,因此此处的第 4 步不会执行任何操作)。
  5. 它运行git fetch origin,或多或少。这通常会复制来自其他 Git 的所有提交,但不会复制任何分支。但是,您确实获得了他们的所有标签。但是,使用 时--depth 1,您不会获得所有提交,也不会获得所有标签,也不会获得所有分支。4
  6. 最后,从另一个 Git 获得所有(或几个,或一个)提交后,您的 Git 使用您提供的参数--branch来选择在您自己的 Git 存储库中创建哪个分支。如果你没有使用--branch,你的 Git 会询问他们的 Git他们推荐哪个分支名称。不过,这里有一个奇怪的标签特殊情况。

由于您确实同时使用了--depth(1) 和--branch(带有标签名称),因此您会得到两种特殊情况的行为:

  • 您的 Git 会生成 Git 所谓的单分支克隆,也就是说,不会费心从您没有特别请求的任何分支名称中获取最后一次提交和更早的提交。

  • 而且,由于您的参数--branch标签名称而不是分支名称,因此您实际上根本没有从它们那里获得任何分支。您只需复制一个标签名称指定的一个提交。然后,您的 Git 根本不创建任何分支名称,并检查一个提交,因为 Git 称之为分离的 HEAD

由于您使用了--depth没有标志的--no-single-branch标志,因此您得到了一个单分支克隆;由于您选择的分支并不是真正的分支,因此您得到了一个no -branch 克隆。这种克隆使用起来非常混乱。它的主要用途是进行单个构建,例如,作为发布构建。不适合做真正的工作。

一般来说,那些刚接触 Git 的人应该避免单分支克隆,避免参数--depth并且在使用. (从某种意义上说,完全不使用该选项可能会更好,而是提供选项 to ,这使得它完全跳过第 6 步。但是,您必须自己做或最初做,这不是最方便的开始方式,即使这只是一个额外的步骤。)--branchgit clonegit clone--branch-ngit clonegit checkoutgit switch


1从技术上讲,标签名称可以包含提交以外的其他内容的哈希 ID——但通常,标签会命名一个特定的提交,即使它是间接的。我包括这个脚注只是为了在技术上是正确的(最好的正确)。

2从技术上讲,如果您强制使用标签,您可以移动它,并且非常旧的 Git 版本(早于 1.8.2)在某些情况下会意外地将分支名称规则应用于标签名称。这在很久以前就已经修复了,但是一些系统仍然带有 Git 1.7(!)。如果您使用的是这样一个古老的系统,您可能应该升级,如果可能的话。GitHub 正在使用更现代的 Git(实际上 GitHub 有时会驱动一些对Git的更新),所以他们至少没有这个标签问题。

3你可以告诉git clone接管一个现有的空目录,但这不太常见——没有太多理由这样做——也不是你在这里做的。

4这里的细节非常复杂,尽管有充分的理由。去掉--depth 1,你得到所有的提交——好吧,所有其他 Git 愿意交出的提交,在使用 GitHub 时以某些与拉取请求相关的项目为模——以及所有的标签,即使有--branch参数。添加--no-single-branch--depth 1,您将获得他们所有的分支提示提交,也许还有更多标签。这就是一切变得复杂的原因。


推荐阅读