与往常一样,您可以挑选合并,也可以恢复合并的恢复。如果您选择选择合并,则必须提供父编号,就像您必须提供父编号才能恢复合并一样。
如果您不希望提交结果,即使cherry-pick 或revert 命令自行成功,您也可以告诉该命令不要执行提交步骤。或者,您可以允许提交,然后使用 git reset --soft HEAD^ 或 git reset --soft HEAD~1 将当前分支向后移动一步 - 几乎与删除提交本身相同 - 根本不改变索引和工作树的内容。
(我说“几乎相同”是因为提交继续存在,并且默认情况下至少受保护 30 天,因为它的哈希 ID 至少存储在 reflog 条目中。)
替代品
然而,这可能不是最明智的整体策略。
假设你有这样的东西:
...--o--o-----*---------M--F--W--G--H <-- mainline
\ /
A--B--C--D--E <-- feature
其中M 是错误合并,A--B--C--D--E 是用于尝试生成某些功能的原始提交链。提交 W 是合并 M 的还原(w 是一种颠倒的 m),并且可能还有其他各种提交,例如 F 到 H。
提交M 是/做了什么——当然除了是一个合并——是它根据合并基础的差异对其第一个 父级(*,上面)进行更改A 的父级到最后一个 feature 提交 E。所以它引入了一大组更改,而您现在发现这组更改是错误的。提交 W 引入了另一组大的变化:那些完全撤消 M 的变化。
如果您现在恢复W,或精选M,您将获得另一组重大更改。如果您在没有提交尚未(或退出)的情况下执行此操作,您可以通过对工作树大惊小怪来选择性地应用或撤消这些更改(也许使用您的索引来这样做,或者完全手动) 然后git adding 修改后的大更改并提交。但这会给您的新提交 I 带来另一大变化:
...--o--o-----*---------M--F--W--G--H--I <-- mainline
\ /
A--B--C--D--E <-- feature
最后一次你添加了一大堆更改,这是错误的。一次一个地逐步引入更改可能是个好主意,这样每个更改都可以单独测试,就像A-B-C-D-E 序列一样。
事实上,这个序列可能是一个很好的起点。假设您要将A-B-C-D-E 序列中的每个提交复制到新(但已更正)提交:A',然后是B',然后是@987654347 @, 等等。如果A 本身是正确的——如果所有问题都在,比如B 和更高版本中——无论如何都要复制它:
A' <-- feature.1
/
...--o--o-----*---------M--F--W--G--H <-- mainline
\ /
A--B--C--D--E <-- feature
重复B 到E:
A'-B'-C'-D'-E' <-- feature.1
/
...--o--o-----*---------M--F--W--G--H <-- mainline
\ /
A--B--C--D--E <-- feature
现在您有了一个正确(且经过测试)的修订功能分支,您可以照常合并:
A'-B'-C'-D'-E' <-- feature.1
/ \
...--o--o-----*---------M--F--W--G--H---------------M' <-- mainline
\ /
A--B--C--D--E
此时没有什么特别的要求,feature.1 分支完全可以一分为二,以定位新增功能中的任何 新 错误,这些错误仅通过名称和意图相关(但不提交哈希)到最初添加的有缺陷的功能。
事实上,既然你知道了,你可能已经使用 git bisect 来找到 A-B-C-D-E 中的哪一个引入了错误,所以如果你可以将A 到E 批量复制到A' 到E'(尚未合并),然后您可以运行git rebase -i 并输入明智的edits 来修复它们,或者为此使用 Git 的自动压缩/自动修复功能。
您所需要的只是“批量复制”操作......事实证明,它已经内置到git rebase,作为--no-ff 选项,如@所述987654321@.