在一个分支上删除Git提交记录

7
我该如何删除由master分支衍生的提交?
我通过Git subtree将一个大型库和丰富的提交历史(在我的代码之前)添加到了一个子目录中。 我想回溯地压缩整个历史记录,但仍然能够合并库中的新提交。
我尝试过各种组合的git rebase,但从未得到预期的结果[*]。
我的存储库看起来像:
A---B-----------F---G master
               /
  ... C---D---E

我希望它看起来像这样:
A---B-----------F'--G' master
               /
              E'

或者:

A---B-------E'--F'--G' master

[*]:

  • git rebase --onto C E master
  • git checkout F; git rebase --onto C E master
这是两个关于Git技术的命令。第一个命令表示将当前分支(即master)从E版本开始重新应用一次提交,直到C版本。第二个命令表示切换到F分支,并将F分支从E版本开始重新应用一次提交,直到C版本。

这样挤压会影响合并。你为什么要挤压它?只是为了清理gitk / git log输出吗? - Vi.
是的,还有之前的所有提交总共达到了几百兆字节的事实。 - Gingi
你将库的开发历史记录集成到项目仓库中导入的决定很奇怪。 - Deestan
你确定将其限制在最后一次提交会节省很多空间吗? - Vi.
为了更清晰的输出,您可以使用子模块。为了节省空间,您可以尝试以浅层模式克隆该库。 - Vi.
1个回答

1
  1. 这是历史编辑。你最终会得到像下面这样的东西

    A---B-----------F'---G' master
                   /
                  E'
    
  2. 在此之后合并会有问题,因为Git将无法找到您的历史记录和库历史记录之间的共同父级。

  3. 要实际执行它,您需要

    1. 重置到B(创建标签或分支以保留G)
    2. 使用--no-commit执行合并。
    3. 在此处重新基于或挑选G(它将成为G')

    历史记录将如下所示

    A---B-----------F'---G'
    

为了进行库的浅层克隆,您需要执行以下操作(警告:未经测试):

  1. 将从 F(不包括)到 G(包括)的提交保存到补丁中(git format-patch F --stdout > ~/saved_commits.patch
  2. 重置为 B。确保没有分支指向 F、E 或 G
  3. 删除远程以及它的引用命名空间 git remote rm
  4. 擦除 reflogs:git reflog expire --expire=now --all
  5. 从 git 中实际删除内容:git gc --prune=now。现在您应该看到仓库已缩小。
  6. 重新添加 library 的远程。
  7. git fetch --depth=10 libraryremote
  8. 重复合并(通常方式)
  9. 应用保存的提交(git am ~/saved_commits.patch)。

要迁移到子模块解决方案(可能是最佳选择),您需要回滚到合并之前的状态并设置子模块,然后将每个合并替换为子模块的更改提交ID。与将项目目录拆分为子模块的情况不同,我不知道这个问题的自动化解决方案(但可以以类似的方式实现)。


为什么 E' 的父节点不是 F' 而是 F(同样的情况也适用于 F'G)? - Gingi
提交号等于提交哈希。改变父级意味着改变此提交,这意味着改变此提交的哈希,也就是改变此提交的编号。历史编辑会产生连锁反应,影响到最近的所有提交。 - Vi.
这里(第三点)有关于你在问题中提到的操作的说明,但这将会破坏合并。你需要什么?1.具体的操作命令;或者2.切换到子模块的想法;或者3.如何浅克隆库的想法? - Vi.
谢谢@vi。我想我想要浅克隆这个库。我曾经把这个库作为子模块,但是后来改成了子树,因为它看起来更容易管理(我错了!)。我正在尝试使用各种filter-branch命令将其重新引入为子模块,但我想看看浅克隆包含什么。 - Gingi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接