好的,根据 Philip 的回答,我对移植、替换和过滤分支进行了一些研究。
因为我想要实现的是重写历史,假设我首先正确地布置了我的存储库,所以我决定解决这个问题的方法是将每个分支的头部嫁接到前一个分支的尖端,然后运行 git filter-branch 使更改永久化。
在新的工作流程下,当更改完成并准备好发布时,它将被合并到发布分支中。如果您检查历史记录,我希望它看起来像是发生了这些合并,并且已经解决了有利于原始分支头的任何问题。
如果您过于仔细地查看结果,您会注意到实际上没有合并提交——每个嫁接的“合并”都直接导致下一次提交。这对我来说并不是一个真正的问题,因为有几十个备用分支漂浮在周围,所以我打算让它悬而未决。
嫁接
我创建了文件.git/info/grafts
。对于此示例,grafts 文件中将有两个条目 - 每个新分支父级都有一个条目。
我犯的第一个错误是忘记包含提交的原始父级——我对 master 的一半附件消失了,我花了大约一半的过程才注意到。
第二次我得到了嫁接文件的内容
[commit] [parent] [parent]
hash2 p2 hash1
hash4 p3 hash3
打扫
我最终得到了一些未跟踪的文件,这些文件已在我的工作目录中浮动的早期提交中被删除。我不确定它们如何在那里结束的机制,但我知道它们保存在我的提交历史中,所以我只是删除了工作目录副本并运行git reset --hard
良好的措施。
branch-C 已经指向新发布分支的尖端,所以我将重命名它:
% git branch -m branch-C release
移植过程的下一步将是使移植物永久化。这将需要使用git filter-branch
来完全重写提交树
重写历史现在对我来说没问题,因为我是唯一真正使用这个存储库的人。有趣的故事,我清理它的主要原因是因为我打算很快与其他人分享 repo,而且我不想在其他人依赖稳定后尝试修复布局而头疼历史。
因为我将重新创建所有这些提交,所以我不希望旧的分支指针徘徊,保持我旧的、死的提交树可见。
% git branch -d branch-A
Deleted branch branch-A (was hash1).
% git branch -d branch-B
Deleted branch branch-B (was hash3).
由于移植,git 没有可抱怨的悬挂提示,因此删除工作顺利进行。
我还在异地同步存储库,所以我的跟踪分支也会保留那些死树。这将在稍后通过 a 解决push --force
,但现在,我只是要放下我的遥控器,这样当我在本地仔细检查我的更改时它不会让我感到困惑。
% git remote remove origin
改写历史
好吧,是时候做一些不可思议的事情了。我的本地 git 存储库具有正确的分支布局,除了发布和主分支的提示之外,没有指向任何提交的指针。
我已经检查了release
分支。
没有争论,git filter-branch
将走下树并重写历史以使我所有的移植物永久化。
% git filter-branch
Rewrite (...) (73/73)
Ref 'refs/heads/release' was rewritten
到目前为止,我还没有在我的原始计划中创建任何我想要的闪亮标签——那是因为标签指针会指向失效的提交哈希。
现在我已经检查了结果并且我的存储库看起来像我想要的那样,我将清理嫁接文件并添加这些标签。
.git/info/grafts
现在正在嫁接我不关心的提交,因此,我可以放心地完全删除文件,或者清除有问题的条目。
% rm .git/info/grafts
提交树看起来仍然正确,所以我已经完成并将所有我想要的标签添加到各种版本中。
重写历史还有最后一步——我喜欢同步到的远程存储库。
我正在重新添加我的遥控器,这会使我的提交树在一段时间内看起来很纠结和生病。
% git remote add origin (...)
起初我尝试只做一个常规的git push --force --all
,但实际上并没有删除已失效的分支。有一个选项,它被称为--prune
.
% git push --force --all
Counting objects: 161, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (61/61), done.
Writing objects: 100% (86/86), 9.06 KiB, done.
Total 86 (delta 48), reused 0 (delta 0)
To (...)
* [new branch] release -> release
% git push --force --all --prune
To (....)
- [deleted] branch-A
- [deleted] branch-B
- [deleted] branch-C
一切都很完美,所以我还删除了 git filter-branch 为发布分支制作的备份信息:
% rm .git/refs/original/refs/heads/release