说我有这个:
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匹配,我可以安全地删除第一个分支。
...有没有办法在第二个分支的某处存储元数据......
不直接,没有。
请记住,每个分支名称只是一个指向提交的(可移动)指针,具有特殊属性,如果使用git checkout
来“分支”,git commit
会自动移动指针。各种其他命令愿意以各种方式移动它:例如,git merge --ff-only
将以快进方式移动当前分支名称,而git reset
将任意移动它。
那么:你在哪里可以存储元数据?这有点棘手。
Git由两个主数据库组成:存储库本身是一个键值存储,其中哈希ID作为键,存储库对象(blob,树,提交和注释标记)作为值。与此同时,refs/heads/*
中的引用分支名称,refs/tags/*
中的标记名称,refs/stash
中的存储区等等 - 是一个键值存储,对键有一些略微奇怪的约束(参见大多数的git check-ref-format
),其值为哈希值标识。
由于您的目标是(我认为)将分支名称与两个不同的哈希ID相关联,因此一种明显的方法是在refs
中创建自己的命名空间。假设我们选择refs/bases/
。对于名称为B(例如全名refs/heads/B
)的分支,您只需要创建一个refs/bases/B
。您可以在refs/bases/B
中存储的唯一内容是哈希ID,但这正是您要存储的内容,因此您已完成。
您是否希望存储多个简单的哈希ID或其他内容,例如,如果您想存储另一个名称,则需要某种数据对象。您的选择是四种对象类型中的任何一种,但其中两种受到强烈约束:树或提交必须正确格式化。其中一个是弱约束的:带注释的标记对象必须包含另一个对象的哈希ID - 带注释标记的目标 - 然后可以包含任意文本。最后一个,blob,不受约束,因为它可能包含任意文本。
要创建带注释的标记对象,请使用git mktag
。有关所需的标记格式,请参阅其文档。
要创建blob,请使用git hash-object -w
,可能使用--stdin
;看它的文件。
两者都输出一个哈希ID,然后您可以将其设置为要存储在refs/bases/B
或refs/xyz-meta/B
下的哈希ID或您选择的任何名称空间。
对于大多数Git用法,工作方式不是存储基本分支名称,也不存储基本提交哈希ID。相反,使用set subtraction来请求可达提交,格式如下:
这正是git rebase
对你传递它的参数所做的事情,例如:当你运行git checkout feature; git rebase develop
时,Git枚举从feature
可以访问的所有提交,减去从develop
可以到达的所有提交。这在Git中很常见,它有git rev-list
语法:develop..feature
表示feature ^develop
,意思是“提交可以从feature
到达,不包括可以从develop
到达的提交”。
(你可以通过你的元数据技巧获得的是自动记住适当的名字 - 但事实证明,在实践中,大多数人似乎并不需要这个。对于你的特定用法,它可能是一件好事,虽然我把这部分放进去是因为我相信将来,其他人会找到你的问题和这个答案,并认为这是一个聪明的方法来记住每个派生分支的“基础分支”。它是什么,但那不是这样的一个聪明的事情。)