如何调试大型git提交?

时间:2013-10-17 13:02:55

标签: git debugging

好的,情况就是这样:

几年前,我们在代码库中对多个文件进行了多项更改,并且一次性提交了所有文件。这些变化中的某处隐藏了一个错误。使用git bisect,我很快就能找到罪魁祸首提交,但是这个提交的变化量让我不那么热情了。

使用git bisect轻松找到一个糟糕的提交是一件轻而易举的事情,但是一旦发现,追踪单一变化的最佳方法是什么?将受影响的文件逐个还原为以前的版本?

3 个答案:

答案 0 :(得分:4)

除非您非常了解在大型提交中发生的所有更改,否则这可能非常繁琐。

通常,非常大(糟糕的大)提交涉及许多不同的更改。您需要做的是从概念上隔离所有这些更改并重写不同的提交。

我建议根据以下4项标准细分变更:

[NEW]涉及与单个识别的技术级功能相关的所有代码(与用户级相对,可能涉及多个技术级功能)

[RFG]任何行为不变的变化。保留执行的行为和API(接口)

[CHG]实施任何代表规格/要求变更的内容

[FIX]任何可能改变行为的变化,使其符合编码背后的意图。

然后,git-wise这就是你需要做的事情:

  git checkout <bad commit SHA1> -b CULPRIT

这将创建一个“CULPRIT”分支。我总是将这一个作为参考,因为您可能需要执行以下步骤的许多繁琐的迭代。作为旁注,沿途保持部分参考有助于(作为分支或标签)。

  git reset HEAD^ --mixed

这将撤消提交,就好像来自提交的所有更改都作为前一次提交的非暂存更改的补丁一起应用。然后使用

  git add --patch

您可以更改这些更改的子集。不要犹豫使用[s] plit选项逐行单独选择更改。有时候,你无法避免一个版本来挑选你想要的变化。并且我在上面建议的新的,RFG,CHG,FIX方案中分解了多次提交,并根据需要重写了许多提交。

注意:

  • 暂存不编译的新提交
  • 暂存一个产生“琐碎”运行时错误的新提交(例如segfault)
  • 需要合并的子提交才能使事情发挥作用

...因为我们的目标是使二等分工作。此外,确保您的新提交与git diff的旧提交相同,新的HEAD提交会再次使用CULPRIT,以确保您没有引入进一步的更改。

这首先是一种痛苦,需要大量的练习但是一旦你做到这一点就变得足够好,你将成为一个调试之神,受到整个团队的崇拜,然后可以传播形式的小承诺的福音NEW,CHG,RFG和FIX。

答案 1 :(得分:3)

您始终可以在该提交中创建一个分支split the commit into smaller commits,然后从那里继续进行二分。

另外,请记住git bisect只是缩小导致问题的更改的工具。它不能免除你必须分析问题,找到错误,并提出修复。

答案 2 :(得分:1)

由于错误提交中只有少数文件,我选择了一种有点天真的方式来实现它。从接受的答案中得出,这就是我最终做的事情:

1)准备一个未提交的提交版本:

         System.out.println(map.get(compare) != null);

2)分阶段另一个文件:

git checkout <bad commit SHA1> -b CULPRIT
git reset HEAD^ --mixed

3)存储剩余的文件,保持分阶段文件的完整性:

git add <filename>

4)如果错误仍未显示:

git stash --keep-index

5)重复步骤2,3和4,直到出现错误,这意味着之前暂存的文件是罪魁祸首

由于罪魁祸首文件中有几个不相关的更改,我选择继续删除过程,但这次是在代码行(或“hunk”)级别:

6)在罪魁祸首文件中分析各个代码:

git stash pop

7)重复步骤3和4,直到出现错误,这意味着之前上演的大块头是罪魁祸首

我认为我可以更优雅地使用git bisect,但由于错误提交中只有7个受影响的文件,我决定手动执行删除。找到错误代码后,我删除了本地CULPRIT分支。