【问题标题】:How do I use `git rebase -i` after `git merge` without messing things up?如何在 `git merge` 之后使用 `git rebase -i` 而不会搞砸?
【发布时间】:2010-11-11 09:29:04
【问题描述】:

我有以下情况:

  1. 我对本地存储库进行了一些提交,然后将另一个分支(约 150 次提交)大量合并到主存储库中。里面有很多冲突。

  2. 现在,我想将我在合并之前所做的提交移动到推送之前。

通常情况下,我会使用rebase -i

不幸的是,默认行为是打破我所做的一次合并提交,实际上添加了 150 多个提交以掌握到单独的提交中(我知道这就像我要使用变基而不是合并开始)——这对我来说是不好的行为有几个原因。

我很高兴发现 -p 标志用于 rebase,它保留了合并。 不幸的是,这实际上再次应用了相同的合并,并忘记了我在解决冲突方面的辛勤工作。再次——不良行为!

有我想要的解决方案吗?在合并后使用rebase -i 重新排序或编辑特定提交,而无需重复我的合并后操作?

谢谢!

【问题讨论】:

  • 你看过git rerere吗?
  • git rerere 现在无法帮助您,因为它会在您提交合并时记录冲突解决方案......除了在 git 的 contrib 目录中有一个名为 rerere-train.sh 的脚本,它“启动”rerere来自您已经进行的合并提交的数据库。

标签: git merge rebase


【解决方案1】:

这就是我在评论中提到的rerere-train.sh 脚本的作用——本质上它会重做合并,使用您的分辨率,然后让 rerere 看到它。如果您愿意,您可以手动为您的单个提交手动执行此操作:

git checkout <parent of merge commit>
git merge <merged commit>         # if this goes cleanly, we're done
git rerere                        # done automatically if rerere.enabled is true
git checkout <merge commit> -- .  # check out the files from the result of the merge
git rerere                        # done automatically if rerere.enabled is true
git reset --hard                  # wipe away the merge

# and you'd want to follow with git checkout <branch> to return to where you were

但您也可以只将rerere.enabled 设置为true,然后执行这些步骤减去对git rerere 的直接调用——您将在未来设置,只要您解决冲突,rerere 就会自动运行。 我就是这样做的——太棒了。

如果您想直接运行脚本,您可能需要使用rerere-train.sh ^&lt;commit before the merge&gt; &lt;current branch&gt; 之类的参数来运行它。 (^commit 表示法的意思是“不要从这里进入历史”,所以它不会为你的 repo 中的 所有 合并提交而烦恼。)

无论您如何做,您最终都应该记录所需的分辨率。这意味着你可以继续做你的rebase -i,当你遇到冲突时,rerere 将重新使用记录的解决方案。提醒一下:它仍然在索引中留下标记为冲突的文件,以便您可以检查它们并确保它所做的事情是有意义的。完成后,使用git add 签入它们,就好像您自己解决了冲突一样,然后照常进行!

git-rerere manpage 包含对正常使用 rerere 的非常好的、冗长的描述,它从不涉及实际调用 rerere ——这一切都是自动完成的。还有一点它没有强调:这一切都基于冲突大块,因此即使冲突最终发生在完全不同的地方,只要它仍然是相同的文本冲突,它也可以重用解决方案。

【讨论】:

  • 哇,这看起来像严重的 git-fu!
  • @Benjol:解决冲突是一件严肃的事情! (但这并不可怕 - 只需在配置中启用 rerere 并让魔法发生。)
  • @Jez:在去年秋天 kernel.org 关闭之前,这里发布的所有手册页链接基本上都是如此。我认为目前没有人打算尝试找到所有
  • 要在一系列提交上运行rerere-train,请使用.. 表示法,即&lt;merge commit&gt;^..&lt;current branch&gt;。脚本 (github.com/git/git/blob/master/contrib/rerere-train.sh) 只是将 args 传递给 git rev-list --parents 并且答案中指定的语法不会限制所描述的范围。
  • 我希望父提交指的是目标分支中最后一次提交的父提交,合并发生的地方......合并提交有两个父提交,包括源分支中的一个。跨度>
【解决方案2】:

我已经编写了一个脚本来执行此操作here。有关已知限制,请参阅open issues

您需要先将 rerere-train.sh 安装到您的 PATH 中。在 Fedora 上,这可以通过以下方式完成:

    install "$(rpm -ql git|grep '/rerere-train.sh$')" ~/bin

【讨论】:

    【解决方案3】:

    我使用了用户@Jefromi 的回答中的rerere-train.sh。但是我有这个错误:

    $ ../rerere-train.sh HEAD
    C:\Program Files\Git\mingw64/libexec/git-core/git-sh-setup: line 6: .: git-sh-i18n: file not found
    

    http://kernel.opensuse.org/cgit/kernel-source/commit/?h=linux-next&id=d52b9f00588bb18d7f7a0e043eea15e6c27ec40c我看到了这个:

    迈克尔·马雷克

    git-sh-setup 助手显然从来没有打算被 git 之外的脚本。这在 git 2.10 中变得很明显:

    downloading an older version - 2.3.4 可移植之后 - 我设法使rerere-train.sh 工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-28
      • 1970-01-01
      • 2015-03-26
      • 1970-01-01
      • 2016-11-18
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      相关资源
      最近更新 更多