我如何拆分历史上埋藏的Git提交?

How can I split up a Git commit buried in history?

我把我的历史弄得一塌糊涂,想对它做些改变。问题是,我有一个带有两个不相关更改的提交,这个提交被我的本地(非推送)历史中的一些其他更改包围。

我想在推出这个提交之前将其拆分,但我看到的大多数指南都与拆分您最近的提交或未提交的本地更改有关。这样做是可行的,一个埋在历史深处的承诺,而不必"重做"我的承诺,从那时起?


在REBASE手册页中有一个拆分提交的指南。简要总结如下:

  • 执行一个包括目标提交(如git rebase -i ^ branch的交互钢筋网)并将其标记为要编辑。

  • 当Rebase达到该提交时,使用git reset HEAD^在提交之前重置为,但保持工作树不变。

  • 以增量方式添加更改并提交它们,根据需要进行尽可能多的提交。add -p对于只添加给定文件中的某些更改很有用。如果要为某个提交重新使用原始提交消息,请使用commit -c ORIG_HEAD

  • 如果你想测试你的承诺(好主意!)用git stash隐藏你没有承诺的部分(或在你承诺之前用stash --keep-index隐藏),测试,然后用git stash pop将其余部分返回到工作树。在提交所有修改之前一直进行提交,即拥有一个干净的工作树。

  • 运行git rebase --continue在现在的拆分提交之后继续应用提交。


下面介绍如何使用Magit。

假设commit ed417ae是您想要更改的;它包含两个不相关的更改,并隐藏在一个或多个提交下。点击ll显示日志,并导航至ed417ae:

initial log

然后点击r打开钢筋库弹出窗口。

氧化镁

m修改提交点。

请注意,您现在想要分割的承诺中有哪些@–这意味着head现在处于该承诺中:

氧化镁

我们想将头移到父级,所以导航到父级(47e18b3)并点击x(magit-reset-quickly,如果您使用evil-magit,则绑定到o,然后进入并说"是的,我指在点上承诺"。您的日志现在应该如下所示:

氧化镁

现在,击q进入正常的magit状态,然后使用常规的unstage u命令来解除第一次执行中没有执行的操作,像往常一样执行c命令,然后击s阶段和c命令来执行第二次执行中的操作,完成后:击r打开rebase弹出窗口。

氧化镁

另一个江户十一〔十七〕继续,你就完了!ll现在显示:

all done log


要拆分一个提交并在此之前添加新的提交,并保存的作者日期,步骤如下:

  • 编辑之前的提交

    1
    git rebase -i <commit>^^

    注:也许还需要编辑

  • 樱桃精选进入指数

    1
    git cherry-pick -n <commit>

  • 以交互方式重置索引中不需要的更改并重置工作树

    1
    git reset -p && git checkout-index -f -a

    作为替代方案,只需交互地存储不需要的更改:git stash push -p -m"tmp other changes"

  • 进行其他更改(如果有)并创建新的提交

    1
    git commit -m"upd something" .

    或者,重复项目2-4以添加更多中间提交。

  • 继续重新平衡

    1
    git rebase --continue

  • 如果你还没有推,只需使用git rebase。更好的是,使用git rebase -i以交互方式移动提交。您可以将冒犯行为移到前面,然后根据需要将其拆分,并将补丁移回(如果需要)。