【问题标题】:How do I debug a large git commit?如何调试大型 git 提交?
【发布时间】:2013-10-25 23:44:38
【问题描述】:

好的,就是这样:

几年前,我们对代码库中的多个文件进行了多次更改,并且一次全部提交。在这些更改中的某个地方隐藏了一个错误。使用 git bisect,我很快就能够追踪到罪魁祸首提交,但该提交中的大量更改让我有点不那么热情了。

使用 git bisect 找到一个错误的提交是一件轻而易举的事,但是一旦找到,追踪导致这一切的单一更改的最佳方法是什么?将受影响的文件一个一个恢复到以前的版本?

【问题讨论】:

  • 正如您已经指出的,源代码控制无法为您做更多事情。您实际上只是在问“如何调试我的代码?”没有向我们展示代码,甚至没有告诉我们您使用哪种语言编写代码?
  • 这是一个完美的例子,说明为什么提交应该是小的、原子的、带有明确提交消息的操作。
  • @Gareth:不,我不是在问如何调试代码,所以这里的实际代码是无关紧要的。我正在寻求进一步缩小错误提交范围的最佳方法,即以与 git bisect 相同的方式消除其良好的更改。我认为下面给出的答案很好地表明源代码管理实际上可以做得更多。
  • @JohanFredrikVaren:您也许可以使用 Delta (delta.tigris.org) 创建一个最小的失败补丁。您需要测试应用补丁是否可以让您在提交之前通过一些测试并且仍然因您现在发现的错误而失败。最小化该补丁应该会指出错误的更改。

标签: git debugging


【解决方案1】:

除非您非常了解该大型提交中发生的所有更改,否则这可能会非常乏味。

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

我建议根据这 4 个标准分解更改:

[新] 涉​​及与单独识别的技术级别功能相关的所有代码(与可能涉及多个技术级别功能的用户级别相反)

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

[CHG] 任何代表规范/要求变化的实施

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

那么,git-wise 就是你需要做的:

  git checkout <bad commit SHA1> -b CULPRIT

这将创建一个“罪魁祸首”分支。我总是将此作为参考,因为您可能需要对以下步骤执行许多繁琐的迭代。作为旁注,沿途保留部分引用会有所帮助(作为分支或标签)。

  git reset HEAD^ --mixed

这将撤消提交,就好像提交中的所有更改都作为对先前提交的未暂存更改的补丁应用一样。然后使用

  git add --patch

您可以更改这些更改的子集。不要犹豫,使用 [s]plit 选项逐行单独选择更改。有时,您无法避免一个版本来手动选择您想要的更改。并在我上面建议的 NEW、RFG、CHG、FIX 方案中分解为多个提交,并根据需要重写尽可能多的提交。

注意:

  • 暂存一个未编译的新提交
  • 暂存一个新的提交,该提交会产生“微不足道的”运行时错误(例如 segfault)
  • 需要合并才能使事情正常工作的子提交

...因为目标是使 bisect 工作。此外,通过 git diff 确保您的新提交与旧提交相同,新的 HEAD 提交再次针对 CULPRIT,以确保您没有引入进一步的更改。

一开始这很痛苦,需要大量的练习,但是一旦你足够擅长这样做,你就会成为整个团队崇拜的调试神,然后可以以形式传播小提交的福音NEW、CHG、RFG 和 FIX。

【讨论】:

    【解决方案2】:

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

    另外,请记住git bisect 只是缩小导致问题的更改范围的工具。它并不能免除您必须分析问题、定位错误并提出修复的责任。

    【讨论】:

    • 谢谢。我尝试了“将提交拆分为较小的提交”解决方案,但在某处迷失了方向。像我这样的 Git 新手真的需要为他们详细说明。
    • @JohanFredrikVaren 那里有许多拆分 git 提交的教程,其中一些非常详细地说明了步骤 - 只需 google 即可。我只是链接到看起来很匹配的那个。
    【解决方案3】:

    由于错误提交中只有几个文件,我选择了一种有点幼稚的方法来解决它。从接受的答案中得出,这就是我最终要做的事情:

    1) 准备提交的非暂存版本:

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

    2) 暂存另一个文件:

    git add <filename>
    

    3) 暂存剩余文件,保持暂存文件完整:

    git stash --keep-index
    

    4) 如果 bug 仍然没有显示:

    git stash pop
    

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

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

    6) 在罪魁祸首文件中暂存各个代码块:

    add --patch <culprit filename>
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-22
      • 2012-05-09
      • 2017-02-09
      • 1970-01-01
      相关资源
      最近更新 更多