如何删除前N次提交?

4
如何删除前N个提交并保留其余的提交不变?
换句话说,我想在第n个提交点拆分仓库,选择从第n+1个提交开始的提交,并丢弃从第1个到第n个的提交。
我不知道如何实现这一点。只尝试过git rebase,但它没有起作用。
以下是我使用git rebase所做的操作。
例如,用于测试的存储库为https://github.com/danistefanovic/build-your-own-x.git
  1. Run git rebase -i --root

  2. Mark the first 20 commits as deleted

    d 4b6d12e Initial commit
    d f81138e Add links to issue form
    d 3530d91 Update README.md
    d 506b834 Update README.md
    d 79f41aa Update README.md
    d f9f9113 Update README.md
    d 9c8f134 Add resource type
    d 133469b Update ISSUE_TEMPLATE
    d 3a47f54 Add tutorials #1
    d 0271577 Add tutorial #2
    d 525953b Add tutorial #3
    d 2796fe5 Update ISSUE_TEMPLATE
    d 4f58667 Updated wrong link language from Go to Node.js
    d 0c525a7 Add tutorial #5
    d 0484fca Add OS: Build a minimal multi-tasking kernel for ARM
    d 457d5bb Add tutorial #9
    d 41ba7fc Add tutorial
    d dfbbf0f Add tutorial #11
    d b76dad5 Add tutorial #12
    d cd3bd26 Add tutorial #13
    pick c5f6c94 readme: Add my tutorial on shell
    pick 1f3c285 Add a minimal interpreter, compiler (x86/Arm) and JIT compiler
    ...
    
  3. No luck. I have to handle conflicts manually as show blow.

    $ git rebase -i --root 
    error: could not apply c5f6c94... readme: Add my tutorial on shell
    
    Resolve all conflicts manually, mark them as resolved with
    "git add/rm <conflicted_files>", then run "git rebase --continue".
    You can instead skip this commit: run "git rebase --skip".
    To abort and get back to the state before "git rebase", run "git rebase --abort".
    Could not apply c5f6c94859d852797c26d815e438e6a697c137a9... readme: Add my tutorial on shell
    

更新
移除/切断Git的修订/提交历史 重复。
但没有找到保留时间戳的方法。

@phd 不是同一个问题 - 这个问题是关于删除早于某一点的提交,而不是晚于某一点的提交。 - Enrico Campidoglio
1个回答

4
首先,你是想要删除前20个提交,还是第一个提交后的20个提交?如你在发布的TODO列表中所示,提交4b6d12e并未列出,因此即使操作成功也不会受到影响。这是因为你将4b6d12e指定为上游。如果你想要包含它(且它没有父提交,因为你说你想要删除前20个提交),那么你需要使用--root选项,这样你就不必将提交指定为上游。
其次,你如何定义“删除提交”?如果提交A添加了file1,提交B添加了file2,而我“删除”了提交A,只留下提交B'——那么B'应该包含file1和file2,还是仅包含file2?
如果B'应该仅包含file2,则意味着你正在删除提交A及其引入的更改,则交互式变基与d选项是一种方法。但是,它肯定会导致冲突,你必须手动解决每个保留的提交中修改了现在不再创建的文件(因为最初创建该文件的提交已被删除)的任何冲突。Git无法推断出你希望它执行的操作,因此你必须手动解决冲突。你的问题的方式暗示了你期望这个过程是自动的,但如果你删除了存储库的初始提交及其更改,则这是不可能自动完成的。
请注意,这是一次历史重写。如果存储库与他人共享,并且分支已经被推送(在其中包含了这前20个提交之一),那么
(a) 你必须使用push -f来更新远程分支,以及
(b) 在更新了远程分支后,你将使所有其他用户处于错误状态,而任何不正确的修复程序都会撤消你的更改;因此,如果你想要这个过程成功,你需要与所有其他受影响的人协调。
另一方面,如果B'应该同时包含这两个文件,那么它应该被称为类似AB而不是B'的东西-那么你需要做以下两件事之一:
一种选择是将提交内容进行“压缩”,而非删除[1]。这只需要在rebase -i的TODO列表中为每个提交使用不同的命令即可。如果你只是压缩提交内容,那么就不应该有任何冲突。但这仍然涉及到重写历史,因此上述关于此的注意事项仍然适用。
另一种选择是创建一个浅克隆库。这不是历史重写;它的主要优点是保留了提交标识,因此没有破坏他人的库(并且副作用是,如果未来需要,你可以重新关联已删除的历史记录)。请参阅git commitdepthshallow-*选项。https://git-scm.com/docs/git-clone 然而,浅克隆库并不能通过推送和拉取真正地共享。如果远程需要移除提交内容,你必须用浅克隆库替换该远程库(并且可能还要做镜像处理)。其他所有用户必须更新其克隆库[2]。

[1] 实际上,我并不喜欢rebase命令的这种术语,因为它会促使人们误解提交是由其补丁定义的,从物理层面来看,这是完全错误的。但这就是rebase使用这些单词的方式。

[2] 最后一个观点也凸显出一个可能的问题:无论你选择哪种方法,都不能强制他人舍弃他们克隆库中的那些提交内容。所以如果你移除它们,例如因为它们包含敏感数据,那么问题可能已经变得棘手了。你应该把任何曾经被推送到共享库中的凭证视为遭受了损害。


感谢您的评论。我想要AB文件。我已更新说明,并尝试了squash,但没有成功。 - jungle
@jungle - 嗯,当你提供足够的信息时,也许我(或其他人)会排除你使用 squash 的尝试。目前为止,我们不知道你发出了什么确切的命令,或者在你发出命令时你的 repo 处于什么状态,或者命令生成了什么输出,或者它“没有起作用”的方式是什么。我已经使用过这种技术很多次,许多其他用户也是如此;因此,轻蔑地说“它没有起作用”毫无意义。 - Mark Adelsberger

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