22

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

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

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

4

4 回答 4

17

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

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

长话短说,你只是跑

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

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

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

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

于 2012-08-23T07:18:50.320 回答
8

你可以使用git rerere功能。

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

您可以使用 来检查存储的分辨率git rerere diff

查看本教程以获取更多信息。

于 2012-05-15T13:37:04.333 回答
5

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

于 2012-05-15T15:42:58.000 回答
2

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

我理解这个问题,因为您有一个与master. 通常这种分支风格被称为特性分支,我绝对鼓励使用它们。

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

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

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

代替

  1. 在制品
  2. 在制品2
  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 工具如果需要,可以轻松浏览该功能)您肯定希望在这些分支重新定位为master. 从长远来看,不仅你的变基会更容易,而且历史是可读的。

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

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

于 2016-06-23T12:41:44.940 回答