首页 > 解决方案 > 如何摆脱警告“忽略损坏的 refs/heads/animate2”,其中 animate2 是分支名称

问题描述

当我这样做时会显示此警告

git 分支

我想在某个时候我删除了 animate2 分支,但可能是它有未提交的更改或其他什么,我不记得了。

标签: git

解决方案


您可以删除引用,尽管这可能有点棘手:请参见下面的示例。或者,您可以克隆您的克隆,或者如果其中没有任何尚未保存在其他克隆中的有价值的内容,请删除整个克隆。

鉴于此特定引用是分支名称 animate21您可能会丢失包含该分支中的所有提交,2但如果 ref 被“损坏”,则它已经不保护提交。

如果没有您特定的损坏参考来测试,我只能创建自己的:

$ echo bad > .git/refs/heads/foo
$ git branch
warning: ignoring broken ref refs/heads/foo
  dev
  diff-merge-base
* master

任何正常的删除尝试都会失败:

$ git branch -d foo
error: branch 'foo' not found.
$ git branch -D foo
error: branch 'foo' not found.

甚至管道命令git update-ref也受到阻碍:

$ git update-ref -d refs/heads/foo
error: cannot lock ref 'refs/heads/foo': unable to resolve reference 'refs/heads/foo': reference broken

所以我只能求助于手动删除:

$ rm .git/refs/heads/foo

通常不推荐最后一种方法,如果损坏的 ref 已“打包”到.git/packed-refs; 在这种情况下,您需要直接(并仔细)编辑该文件。但它确实适用于我自己破碎的参考。


1 Git 使用的分支master、标签v1.2、远程跟踪名称origin/master以及更多形式都是Git 称为引用的通用机制的特定种类。所有分支名称都有以 . 开头的全名。所有标签名称都有以 . 开头的全名。所有远程跟踪名称都以 开头,然后包含远程名称,再加上另一个斜线。这意味着 Git 只需要一种内部机制来处理所有这些:它只是读取所有 refs,如果其中一个是,则表示分支名称refs/heads/refs/tags/refs/remotes/refs/heads/dev dev

2如果可以从分支名称标识的提交访问这些提交,则该分支“包含提交” 。所有引用仅标识一个特定的提交或其他对象——分支名称受到限制并且必须代表提交,而标签名称可以代表任何对象——但 Git 可以从任何给定的提交开始并通过提交图向后工作。这意味着分支名称只需要指示分支中的最后一次提交。从最后一次提交可到达的所有提交都是分支的一部分。

这反过来意味着许多提交同时在许多分支上。这个可达性属性是 Git 的核心。请参阅像 (a) Git 一样思考


侧边栏:没有分支有任何未提交的更改

我想在某些时候我删除了 animate2 分支,但可能是它有未提交的更改或其他东西......

这绝对不是“破裁判”的事情发生的原因。“损坏的引用”是 Git 中的通用引用机制为其设置REF_BROKEN标志的引用:

/*
 * Reference cannot be resolved to an object name: dangling symbolic
 * reference (directly or indirectly), corrupt reference file,
 * reference exists but name is bad, or symbolic reference refers to
 * ill-formatted reference name.
 */
#define REF_ISBROKEN 0x04

(来自refs.h,第 260 行附近)。

事实上,虽然,Git 中的一个分支......嗯,分支这个词是模棱两可的(请参阅我们所说的“分支”到底是什么意思? ),但在你的脑海中,分支对你应该意味着的两件事是:

  1. 一个name,例如master,在内部将是一个refs/heads/name 或其他一些您将以“类似分支的方式”使用的引用。远程跟踪名称origin/master有点像分支,一些人和文档,包括 Git 的,有时称它们为远程分支,或者至少称为远程跟踪分支名称。(远程分支术语是我认为非常草率的术语,我总是尽量避免使用它。)

  2. 提交图的子集,通过采用类似分支名称指示的提交并向后工作而形成。(参见“分支”到底是什么意思?Think Like (a) Git。)

这两个都不能保存未提交的更改:一个只是一个包含提交哈希 ID 的名称——一个像 的大而丑陋的字符串7c20df84bd21ec0215358381844274fa10515017,另一个是一个提交链。那么......未提交的更改存在于哪里答案是它们在索引和/或你的工作树中。

您的工作树包含一组您可以查看并提供给其他程序使用的文件。您需要一个工作树,因为每个 Git 提交中的文件快照都存储在一个特殊的、只读的、压缩的、仅限 Git 的形式中。在仅 Git 形式中,它们可以从一个提交重复使用到另一个提交,但它们实际上不能更改。如果你不能改变它们,你就不能完成任何新的工作。因此,您需要一个将它们去 Git 化的地方,将它们转换回普通的读/写文件,这就是您的工作树。

索引是一种特殊的Git 数据结构——它实际上主要存储在一个普通文件中.git/index——Git 使用它,位于当前的提交——你签出的那个HEAD——和你的工作树之间。这个东西,这个索引,对于新提交的过程非常重要。它保存了从您现在正在处理的提交中取出的每个文件的副本3,就像工作树保存每个文件的副本一样。索引中的副本采用特殊的冻结 Git格式,但与提交中的副本不同,实际上并没有冻结。您可以随时使用新副本替换它git add获取您的工作树版本并为 Git 准备并覆盖索引版本。

索引是如此重要(和/或“索引”这个名字太糟糕了)它还有两个名字。它也称为staging area,以反映其保存您提议的下一次提交的工作,以及(现在很少)缓存,以反映其位于当前提交和工作树之间的工作。

git status为 commit 进行了一些更改时,这实际上意味着索引中的该文件的副本与HEAD提交中的文件的副本不同。当git status没有为 commit 进行某些更改时,这实际上意味着索引中的文件副本与工作树中的文件副本不同。

因此未提交的更改是索引和/或工作树中的更改。他们实际上根本不在任何分支中。你可以某个分支上——就像git status会说的那样on branch xyz——并且在索引和你的工作树中拥有那些未提交的更改,但它们根本不存在 xyz。如果你做了一个新的提交——它会快照索引中的任何内容,这就是为什么你必须一直git add从你的工作树复制到索引的原因——那么新的提交将成为分支的尖端提交。 现在他们“加入xyz”了,但他们不再是不承诺的。

“删除分支”包括删除分支名称。这就是您所要做的:只需删除 name,并使用它,最后一次提交的存储哈希 ID:您所说的提交是分支的结尾。提交本身仍然存在。如果它没有受到保护——无法访问:再次参见Think Like (a) Git ——Git 最终也会丢弃提交。


推荐阅读