【问题标题】:Smarter rebase avoiding redundant work?更智能的 rebase 避免冗余工作?
【发布时间】:2012-05-15 13:16:48
【问题描述】:

我在使用长变基时遇到的一个问题是必须解决冗余冲突。假设我有一个包含一系列提交的分支,它不断修改一个函数,而最终提交完全删除了该函数。

当我执行rebase master 时,Git 会天真地依次应用每个提交。这意味着我需要用 master 的提示来解决这些提交中的每一个——即使最终这些工作都被浪费了。

什么是处理这种情况的好方法?也许我应该为整个分支生成一个补丁,然后将其应用于 master?如果是这样,有什么办法可以保留一些历史吗?想法、建议等。

【问题讨论】:

  • 我认为你需要使用git rerere,但我没有这方面的经验。
  • 据我了解,如果您将来需要重新应用合并,rerere 会有所帮助。但我试图避免解决它们一次。
  • 如果你有一个特性分支,它添加了一个稍后在同一个特性分支中删除的函数,你可能应该了解git rebase -i并在master之后重新定位它之前修复特性分支。 (功能分支应包含正确顺序的最少补丁,交互式变基有助于获取该目标。)

标签: git git-rebase git-diff


【解决方案1】:

您想使用 git rerere 并结合使用 rerere-train.sh 从历史提交中教授 rerere 数据库(您可能已经在 /usr/share/doc/git/contrib/rerere-train.sh 拥有它)。这允许 git 自动使用从历史中学到的合并冲突解决方案。

警告:你基本上是通过盲目地使用历史字符串替换来修复冲突的合并,从而使 git 重写源代码。您应该在 rebase 之后查看所有冲突的合并。我发现gitk 可以正常工作(它只会显示冲突解决作为合并补丁)。我只对rerere 有过很好的体验,你可能没那么幸运。基本上,如果您的历史记录确实包含损坏的合并(即技术上错误地完成的合并,然后在后续提交中修复),您不想使用历史记录中的rerere,除非您希望完成类似的损坏合并自动为您服务。

长话短说,你跑吧

git config --global rerere.enabled 1
bash /usr/share/doc/git/contrib/rerere-train.sh --all

然后是你真正想做的变基,它应该会神奇地工作。

在全局启用rerere后,以后不再需要从历史中学习。只有在启用rerere 之前已经完成冲突解决之后,才需要使用学习功能。

附言。我找到了另一个问题的类似答案:https://stackoverflow.com/a/4155237/334451

【讨论】:

  • @user230137 你能详细说明一下吗?您是否收到一些错误消息或 git 无法神奇地为您进行合并?您确定合并冲突与历史上完成的合并相同吗?
  • git 无法进行合并。你怎么知道合并冲突与历史上完成的合并相同?
  • 如果您使用rerere 并且没有自动完成合并,则冲突不完全相同。仅当您或其他使用相同存储库的其他人较早解决了相同的冲突时,才可以从历史合并中教授 rerere。如果合并冲突不相同,则使用kdiff3 可能会获得最佳结果。但请注意,kdiff3 的尝试有点过头了,它有时会“自动解决”您的冲突而无需寻求指导。始终查看使用kdiff3 所做的更改!如果您已安装并运行 git mergetool,将自动使用 kdiff3
【解决方案2】:

您可以使用git rerere 功能。

您必须使用 git config --global rerere.enabled 1 启用它,之后,您解决的每个冲突都会被存储以供以后使用,并且解决方案会在相同的上下文中重新应用。

您可以使用git rerere diff查看存储的分辨率。

查看tutorial 了解更多信息。

【讨论】:

  • 所有有用的信息,但并没有真正解决我的问题 - 即如何避免首先进行任何冗余合并。
  • 也许你可以使用git rebase -s recursive -X theirs master来自动解决所有冲突,使用原始版本的函数或-X ours使用新的分支函数,如果你不关心,小心,这会用于所有的冲突,不仅在那些函数中。抱歉,如果没有有关 repo 的更多信息,我无法为您提供帮助,我想您应该进行更多的集成合并,而不是一次尝试合并数周/数月的开发。
  • 是的,我正在学习很多“不该做什么”:) 焦虑的另一个主要原因是拥有庞大的源文件和庞大的功能。事实证明,在这种情况下合并更改要困难得多。而对于小型模块化函数,我认为您会遇到更少的合并冲突,并且它们会更容易解决。 (并不是说我们不知道长函数不好,而是我不知道这个特殊原因。)
  • 合并毛茸茸的长函数的并行开发线将是一项艰巨的任务,无论是由计算机还是由人类完成。大函数或方法通常有很多很多的变量,这是合并中最有问题的部分,恕我直言。
【解决方案3】:

为什么不将squash 多余的补丁放在一个初始的交互式 rebase 中(首先重新排序它们,使它们在一起),这样您就已经清除了序列的“修改然后删除”方面。在此阶段,您可以选择性地使用提交中的帅哥(例如,使用 git gui)。然后,这将为您提供更好的最终干净变基序列。

【讨论】:

  • 是的,我想我会试试这个。它给了我一点历史(即提交仍然来自某个地方,并且它包含所有丢失的提交消息)但应该简化流程。
  • 区分“squash merge”和git rebase -i的“squash”操作很重要。前者压缩了整个特征分支,而后者只组合了选定的部分。您可能需要使用editsquash 并使用git rebase -i 重新编码补丁以获得非常好的结果。学习曲线有点陡峭,所以一开始可能会觉得很难,但一旦你完全理解了这个过程,就会变得更容易。
【解决方案4】:

(这是我对问题的第二个答案。在第二次阅读时,我认为最初的问题可能与我最初理解的有点不同。)

我理解这个问题,因为您有一个与 master 平行的开发分支。通常这种分支风格被称为特性分支,我绝对鼓励使用这些。

应该始终尝试保持功能分支的清洁。在实践中,如果您从未犯过任何错误,您需要一个具有提交的功能分支。对我来说,这意味着我要付出很多,后来git rebase -i 来修复这些错误,当我后来知道这些错误时。

当你的功能分支准备好时,它应该看起来像

  1. 添加 API 来做事 X
  2. 为角落案例 Z 修复现有 API Y
  3. 使用 X 和 Y 添加特征 B(也适用于 Z 情况!)
  4. 改进功能 B:做魔术 E

代替

  1. 在制品
  2. WIP2
  3. 添加 API
  4. 移动 API 来做 X
  5. 添加功能 B
  6. 再三考虑,重命名 X 的参数
  7. 修复功能 B
  8. 修复 X ​​的 API
  9. 修复角盒 Z
  10. 也为 API Y 修复角落案例 Z
  11. 做魔术 E
  12. 提交缺少的文件

如果您随后将您的功能分支重新设置为最新的master 分支,则更改很高,仅提交Fix existing API Y for corner case Z 可能会导致冲突。如果该提交是修改现有 API 的最小更改,那么修复冲突应该很容易。此外,只有在其他提交完全修改了您的最小更改所涉及的行时,才会出现这种冲突。

如果你做特性分支和 rebase 特性分支而不是合并(我的首选风格是 rebase 以便可以快进,然后做 git checkout master && git merge --no-ff feature-branch-x 并在合并提交中记录整个事情——这样可以保留完整的历史记录的分支,并允许 GUI 工具在需要时轻松导航该功能)您肯定想要 keep your feature branches clean 在将这些分支重新定位到 master 之前。从长远来看,不仅你的 rebase 会更容易,而且历史是可读的。

因此,在上面的示例中,可以rebase -i <old-enough-sha1> 并将提交重新排序为 3+4+6+8、10、1+2+5+7+9、11+12,其中 + 表示 squash。 Git 也允许拆分和编辑现有的提交,但通常更容易将提交保持在非常小的范围内,然后在 其中一些 压缩。请注意,在此示例中,即使原始提交编号 10 在原始第一次提交之前结束。这是正常的,反映了您的实施并不完美的现实。不过,这不需要存储在版本历史记录中。

在您的情况下,听起来您有一个功能分支,其中多个提交添加和删除相同的东西。将这些提交压缩为单个提交(可能最终没有更改,这没关系)。仅当功能分支看起来很干净时,才将您的功能分支重新设置为 master。一定要学会使用git gui 或其他一些工具,让提交更改的lines 而不是files 变得容易。每个提交都应该是一个修改一个理智的东西集合的更改。如果您添加新功能 X,则同一提交不得修复现有功能 Y 或添加有关 Z 的缺失文档。即使这些更改是对同一 文件进行的。对我来说,这就是 Linus Torvalds 说“files do not matter”时的意思。

【讨论】:

    猜你喜欢
    • 2011-06-16
    • 2017-08-10
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    相关资源
    最近更新 更多