在分支(元数据)中存储关于它从 "parent" 分支分叉的点的信息

Store information in branch (metadata) about which point it diverged from "parent" branch

假设我有这个:

latest_commit=`git rev-parse HEAD`
git checkout -b "foo_$latest_commit"
git reset --soft "origin/dev"

我正在做的是跟踪第二个分支与第一个分支的分歧。但是,不是将提交 ID 放在第二个分支的名称中,有没有一种方法可以将元数据存储在第二个分支的某个地方,这样我就不必在分支的名称中放置一个长的提交 ID?

最终,我想做什么?在使用 git reset --soft 压缩提交后,我将把 foo_$latest_commit 合并到集成分支中。稍后,我希望能够安全地删除第一个和第二个分支。如果第一个分支的提示与第二个分支名称中的提交 ID 匹配,我可以安全地删除第一个分支。

... is there a way to store metadata somewhere in the 2nd branch ...

不直接,不。

请记住,每个分支 name 只是一个指向提交的(可移动)指针,如果您使用 git checkout 获得特殊的 属性 "on"分支,git commit自动移动指针。各种其他命令愿意以各种方式移动它:例如,git merge --ff-only 将以快进方式移动当前分支名称,而 git reset 将任意移动它。

那么:可以在哪里存储元数据?这有点棘手。

Git 由两个主要数据库组成:存储库本身是一个键值存储,哈希 ID 作为键,存储库对象(blob、树、提交和注释标签)作为值。与此同时,引用——refs/heads/* 中的分支名称、refs/tags/* 中的标签名称、refs/stash 中的存储等等——是一个键值存储,在键上有一些稍微奇怪的约束(大多数见 git check-ref-format),其值是哈希 ID。

由于您的目标是(我认为)将 分支名称 与两个 不同的 哈希 ID 相关联,一个明显的方法是发明你自己的名字space refs。假设我们选择 refs/bases/。对于名称为 B 的分支(例如全名 refs/heads/B),您只需创建一个 refs/bases/B。您唯一可以存储在 refs/bases/B 中的是哈希 ID,但这正是您要存储的内容,所以您已经完成了。

如果您希望存储的不仅仅是一个简单的哈希 ID,或者不是简单的哈希 ID,例如,如果您想要存储另一个 name,您将需要某种数据对象。您可以选择四种对象类型中的任何一种,但其中两种对象类型受到严格限制:树或提交必须正确格式化。其中之一是弱约束:带注释的标签对象 必须包含另一个对象的哈希 ID(带注释的标签的目标),然后可以包含任意文本。最后一个 blob 不受约束,因为它可以包含任意文本。

要创建带注释的标签对象,请使用 git mktag。请参阅其文档以了解所需的标记格式。

要创建 blob,请使用 git hash-object -w,可能使用 --stdin;请参阅其文档。

两者都输出一个哈希ID,然后您可以将其设置为要存储在refs/bases/Brefs/xyz-meta/B或您选择的任何名称-space下的哈希ID。

最后一个音符

对于大多数 Git 用法,工作方式不是存储基本分支名称,也不是基本提交哈希 ID。相反,使用 set subtraction 请求 reachable 提交,形式为:

  • 所有可从名称 T 访问的提交(提示);但是
  • 排除名称 S 可到达的所有提交(停止)。

这正是 git rebase 对您传递的参数所做的,例如:当您 运行 git checkout feature; git rebase develop、Git 枚举所有提交 可从 feature减去可从develop到达的所有提交。这在 Git 中很常见,它有一个 git rev-list 语法:develop..feature 表示 feature ^develop,表示 "commits reachable from feature, excluding commits reachable from develop"。

(元数据技巧可以自动记住适当的名称,但事实证明,在实践中,大多数人似乎并不需要这个。对于您的特定用途,它很可能是不过,这是一件好事。我把这一部分放在里面是因为我相信将来其他人会找到你的问题和这个答案,并认为这是为每个派生分支记住 "base branch" 的聪明方法。它是,但这不是一件聪明的事。)