git BFG 之后的笔记?

git notes after BFG?

我从 SVN 迁移到 git 并且我在每个 git 提交中都有一个注释引用 SVN 修订号。 回购导入后,我使用 BFG 回购清理器从二进制文件和其他垃圾中清除 git 历史记录。 不幸的是,现在我在键入 git log 时看不到注释。我想 BFG 忘记更新对注释提交的引用。 BFG 留下一份 *.txt 报告,其中包含以下格式的旧对象 ID 到新对象 ID 的映射:

0001b24011381e8885683cd1119ba4cb077fa64b c81149b1b52b9e1e1767d6141f292891d715edb5
00024eecdc31f2f6e67018f7d6f00e7c1ad03f1f 326ee3b508e3dd2934ec1f50069195f86ea1a1c7
00028e04dcc2d59bd835b447bd3a207ae481696c 3d18e9b9d3336e59d62093200b81603ffefcc747

你能推荐一些脚本来根据上述映射快速修复注释吗?

PS:我几乎可以肯定问题是由没有更新的 refs 引起的,因为当我在第二位输入 git notes 时,我可以看到 BFG repot 中被认为是旧的 refs object-id-map.old-new.txt

[编辑: Git 2.15 版,2017 年 11 月发布,添加 --state-branch 到 filter-branch。此选项将地图保存在第一个过滤器分支操作创建的分支中的文件中。随后的过滤器分支操作将使用现有地图。因此,自 Git 2.15 起,将 --state-branch <name> 添加到您的过滤器分支操作中,然后在新创建的分支中使用映射。]

没有内置的东西可以做到这一点;您将不得不自己编写脚本或程序。从好的方面来说,BFG 给你留下了地图文件:这比 git filter-branch 好得多,后者把它扔掉了,这样你更新笔记所需的信息就没有了。

注释中的底层实现是refs/notes/commits(或者你为core.notesRef设置的任何内容)指向一个普通的提交,你至少在理论上可以git checkout(可能进入您专门为此目的设置的临时工作树)。该树包含名称为带注释的提交的文件——仅略微修改。例如,如果:

0001b24011381e8885683cd1119ba4cb077fa64b c81149b1b52b9e1e1767d6141f292891d715edb5

是一个映射条目,0001b24011381e8885683cd1119ba4cb077fa64b是一个旧的提交,如果0001b24011381e8885683cd1119ba4cb077fa64b有一个注释条目,就会有一个文件name0001b24011381e8885683cd1119ba4cb077fa64b——只是,它可能是 00/01b2...00/01/b2....

所有这些添加的子目录的嵌套深度由注释代码动态管理,总体思路是“根据需要添加尽可能多的树以查找是否有注意,快;但是当很少有以 0001b2... 开头的注释时,没有那么多树占用存储库中的大量 space。尽管您同样速度的原因不妨维护一下。

您的任务是在该树中的 old 名称下找到每个文件,并将其移动(或复制)到 new 与新提交 ID 匹配的名称。由于在这种情况下新名称将是 c81149b1b52b9e1e1767d6141f292891d715edb5,您可以将文件重命名为 c8/1149b1b52b9e1e1767d6141f292891d715edb5,或 c8/11/49b1b52b9e1e1767d6141f292891d715edb5,等等。一旦您重命名了所有文件(通过索引:使用 git mvgit rm --cachedgit add 根据需要),您可以使用 git write-tree 后跟 git commit-tree 将它们变成常规提交对象。使新提交的父级成为现有的 refs/notes/commits 提交,并使用 git update-ref 更新 refs/notes/commits 以指向 new 提交,并且您的注释应该重新出现,post-过滤。

(一旦你有了这样的东西,最好将它与 git filter-branch and/or BFG 本身结合起来。)

我编写了以下 bash 脚本来从旧对象转移我的笔记。该解决方案在单线程中很慢,不确定 运行 多个 git notes 并行命令是否安全。

while read string; do
    hashesArray=($string)
    git notes copy ${hashesArray[0]} ${hashesArray[1]}
    git notes remove --ignore-missing ${hashesArray[0]}
done <object-id-map.old-new.txt