在分支(元数据)中存储有关它与“父”分支不同的点的信息

时间:2018-09-01 02:52:10

标签: git git-checkout

说我有这个:

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合并到Integration分支中。后来,我希望能够安全地删除第一个和第二个分支。如果第一个分支的尖端与第二个分支的名称中的提交ID匹配,我可以安全地删除第一个分支。

1 个答案:

答案 0 :(得分:2)

  

...有一种方法可以将元数据存储在第二个分支的某处...

不直接,不。

请记住,每个分支 name 仅仅是指向提交的(可移动的)指针,具有特殊的属性,即如果您使用git checkout来“进入”分支,{{1 }} 自动移动指针。其他各种命令也愿意以各种方式移动它:例如,git commit将以快进的方式移动当前分支名称,而git merge --ff-only将任意地移动它。

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

Git由两个主要数据库组成:存储库本身是一个键值存储,以哈希ID作为键,存储库对象(blob,树,提交和带注释的标记)作为值。同时,引用(在git reset中的分支名称,在refs/heads/*中的标签名称,在refs/tags/*中的存储区,等等)是一个键值存储,对键有一些奇怪的约束(大多数情况下,请参见refs/stash),其值为哈希ID。

因为您的目标是(我认为)将分支名称与两个不同哈希ID相关联,所以一种显而易见的方法是在{{1} }。假设我们选择了git check-ref-format。对于名称为B(例如全名refs)的分支,您只需要创建一个refs/bases/。您可以存储在refs/heads/B中的唯一东西是哈希ID,但这正是您要存储的,因此就可以了。

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

要创建带注释的标记对象,请使用refs/bases/B。有关必需的标记格式,请参见其文档。

要创建Blob,请使用refs/bases/B,可能使用git mktag;请参阅其文档。

两者都输出一个哈希ID,然后您可以将其设置为哈希ID,以存储在git hash-object -w--stdin或您选择的任何名称空间下。

最后一个笔记

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

  • 所有可从名称​​ T 到达的提交(提示);但是
  • 不包括名称为 S 的所有提交(停止)。

这正是refs/bases/B对您传递的参数所做的事情,例如:当您运行refs/xyz-meta/B时,Git枚举所有可从 到达的提交{{1} },可从git rebase获得的所有提交。这在Git中非常常见,以至于它具有git checkout feature; git rebase develop语法:feature意味着develop,这意味着“从git rev-list可以到达的提交,不包括从develop..feature可以到达的提交”

(元数据技巧可以使您自动记住适当的名称,但事实证明,实际上,大多数人似乎不需要此名称。对于您的特定用法,这可能是一个好习惯我放这部分是因为我相信将来,其他人会找到您的问题和答案,并认为这是记住每个派生分支的“基础分支”的聪明方法。那不是一件聪明的事情。)