使用Git amend修改提交记录而不是创建多个提交记录

3
据我所知,git commit --amend 可以用于修改未完成的提交,使其变得易于理解,修复拼写错误等。然而,有时它可能被(错误地?)用作保持提交历史更清洁的银弹(类似于压缩合并)。
一位工程师提出,在本地开发复杂功能(在分支上)时,他们会反复使用 git commit --amend 直到功能完成。例如:
  • 第1次提交:创建函数 A 和 B 的存根。
  • 第1次修订第1次提交:实现函数 A。
  • 第2次修订第1次提交:实现函数 B。
  • 第3次修订第1次提交:添加服务 X。
原因是他们试图保持提交历史记录干净,并尽可能少地保留提交。
对我来说,这种以修改为中心的方法是新的,因为我通常会通过为每个逻辑上完成的状态添加一个提交来使开发过程更透明。例如:
  • 第1次提交:创建函数 A 和 B 的存根。
  • 第2次提交:实现函数 A。
  • 第3次提交:实现函数 B。
  • 第4次提交:添加服务 X。
据我了解,拥有多个提交可能有助于审查过程,有助于理解单行更改(即使是多年后),并且提供了在开发过程中重置到旧的中间状态的可能性(例如,在开发过程中遇到死胡同的情况下),因为它不会一遍又一遍地被“覆盖”。
此外,由于通常在上游禁用git push --force,一旦提交被推送,--amend 将不再起作用。很可能在团队合作时也会引起问题。
您认为使用“amend”来保持历史记录干净是一种有效的方法,还是可以被视为给定示例的反模式?压缩合并是否被认为是更准确的清理历史记录的方法?
3个回答

3
git commit --amend 命令实际上非常简单,它并不会真正“更改”任何提交记录,并且任何使用该命令的人都仍然会创建多个提交记录。不幸的是,要真正理解这一点有点复杂。但是你真正想问的问题完全不同:“什么情况下使用它是一个好主意,什么情况下不是一个好主意?”
你本来想问的问题没有明确的答案,这是一个主观问题,因此在StackOverflow上并不适合讨论。此外,这是更大的问题中的一部分,这个问题也很模糊:“在一个提交中工作的适当粒度是什么?”
我们无法回答这个问题,但我们可以采取技术方面的方法来回答辅助问题,这些问题将为最终基于个人意见的答案提供支持。具体而言,我们可以查看每个提交的内容和作用,这会使我们涉及到 Git 的特定性,尽管其他版本控制系统中的提交通常在效果上相似(即使底层机制非常不同):
- 提交记录表示组成系统的所有文件的快照。 - 提交记录带有一些元数据:谁进行了此操作,何时进行的,以及可能最重要的“为什么”。提交信息中包含了解释“为什么这次提交存在”的信息。 - 在 Git 中,版本历史“就是”提交记录。Git 通过将自己的特定元数据与用户提供的“为什么这个提交存在”消息一起压缩在提交中来实现这一点。 - 使用历史记录(在Git中就是存储库中的提交)我们可以让计算机做几件自动化的事情。我在这里具体指出的两个是:
1.生成日志(用于任何目的:只是为了阅读以便提醒自己某些事情,或者为发布说明编写更改日志等)。
2.自动化测试并执行二分查找寻找错误。
以上内容并不一定是完整的清单,但我认为它是一个很好的起点。
注意,某种程度上,最后两条也持相反的观点:生成日志的观点认为应该保留较少的提交记录,以便日志更易于阅读和消化,并提供更好的高级(上下文)视角。而二分查找想法则要求应尽可能细小和精细地提交,以便在我们引入Bug时,第一个出现问题的单独提交足够小,可以在阅读diff时很容易发现问题。所以我们应该尽可能少地提交记录,同时尽可能多地提交记录1
如何解决这个问题,这是一个观点的问题。不过,我们可以注意到,最小而合理的提交是独立存在的:在提交之前软件能够正常运行,提交之后软件仍然能够正常运行。如果一组更大的修改(例如添加某个功能)可以分解为两个或多个更小的修改,并且我们更喜欢(按照观点)“更细粒度”的模式,那么我们应该将这个提交拆分成更多的部分。
在某些情况下,一个小的提交实际上可能并没有改进代码的功能,但是仍然被证明是正当的,因为它允许下一个高粒度的提交独立存在。也就是说,我们将基础设施工作拆分成小块并完成提交,编写一个解释清楚的提交消息,解释这个特定的变化是“预备性的”。这将使我们的未来变化变得更加容易。
通常,达到这个点——具有这种颗粒度的提交——需要额外的时间和努力:我们可能会将新功能编写成半打(或更多)混乱、侵入性和/或低质量的提交,只是为了确保这个想法确实起作用并且是有用的。然后,我们回头重构这些碎片成为合理的提交。时间压力可能会阻止这一点,但这是将一个大的提交分解成小而明智的部分的理想方式。
不过,最终,我们必须牢记使用版本控制系统的目标:使我们的工作更加容易、使我们的软件更加可靠、使我们的软件更加易于维护、满足质量控制目标等等。管理层通常具有至高无上的时间目标,这可能会打破所有其他论据。提交颗粒度必须考虑到所有这些因素,并且并不是每个人都会同意正确的颗粒度。
使用 `git log` 的过滤机制,我们可以只查看历史记录中的某些提交,从而在高度详细的单个提交和良好的概述之间取得平衡。不过这需要纪律,Git本身并不强制执行。

0
考虑以下情况。
1. 你将一些代码重构为函数名为`doThisThing`,用`doThisThing`的调用替换了3个几乎相同的代码块,并提交了更改。
2. 在测试过程中,你注意到其中一个调用拼写错误为`doThsiThing`,所以你纠正了这个拼写错误。
你真的认为将`doThsiThing`更改为`doThisThing`值得单独提交,而不是在第一步中修改提交以更正拼写错误吗?
如果你分享这个提交,查看它的人无法也不需要知道你最初是否拼错了函数名。单独的第二次提交对于查看提交历史的任何人都没有提供有用的信息。

原始问题可能存在歧义。您描述了一个明确的用例,即使用amend进行修正,而工程师在实现应用程序/功能的全新方面时甚至也使用amend,而不仅仅是为了纠正拼写错误。请告诉我如何重新表述问题。 - dim
2
在我看来,并没有一个明确的界限,可以说“这个问题足够简单,值得使用--amend,但是任何更复杂的情况都应该分成两个提交”。我的经验法则是,如果另一个工程师对我一开始只使用了一个提交并不感到惊讶,那么我就会使用--amend。(这也引出了一个有些离题的问题,即何时一个提交“太大”,在与其他人分享之前应该拆分成两个提交。) - chepner
非常感谢您的反馈。事实上,我对使用--amend的原因有完全相同的理解。在听取了您的意见后,我重新表述了最初的问题,并且(希望)使问题更加明确易懂。 - dim
在你的例子中,如果紧随其后的提交实际上是对AB进行了实现,我认为创建AB存根的提交几乎没有必要。添加服务X作为一个单独的提交可能是有意义的,除非AB仅仅是为了支持添加X而实现的。在决定是否需要将它们分开或合并之前,我想知道这两个提交中实际上包含了什么内容。 - chepner
决定一个提交中应该包含什么和多少内容,类似于决定一个函数定义中应该包含什么和多少内容。 - chepner

0

哪种方法更好取决于许多因素,包括您用于审查的工具、您的项目是否对提交或提交消息有特定的政策以及团队的偏好。

Git和Linux处理提交消息的方式通常被认为是理想的:每个提交描述一个单一的逻辑变更;具有详尽、描述性的提交消息;并且可以进行二分法(测试套件在之前和之后都通过)。然而,这需要大量的工作和纪律,许多团队和项目不愿意实施。

一些项目希望每个更改最终成为一个单独的提交,因为这样可以避免许多包含无用提交消息并导致历史记录混乱的小型“修复”提交。可以通过以下几种方式来实现:

  1. 继续使用git commit --amend命令。
  2. 构建一个单独的提交,然后使用git commit --squashgit commit --fixup添加额外的提交,在合并之前使用git rebase -i --autosquash命令进行压缩。
  3. 在合并之前,使用git rebase -i命令手动压缩多个提交。
  4. 使用压缩合并。

如果您正在使用需要反复合并两个长时间运行的分支的工作流程,压缩合并绝对是错误的选择,只会导致问题和悲伤。否则,这些选项都是合法的。您可能更喜欢类似于2或3的方法,因为它有助于审查,但最终结果仍是一个提交。

由于我贡献给Git,我按照Git项目要求编写提交,我看到了其中的价值。我不止一次地通过参考提交消息来回答同事关于我最近所做工作的问题。

在开发过程中,我经常使用git commit --squashgit commit --fixup(或git commit --amend)来修复我之前的错误,然后将这些更改压缩以保持整洁的历史记录。如果我试图在拉取请求过程中向审核者提供上下文,我可能会在稍后将这些修复提交推送进行审核再进行合并。

有时,我会实现一系列提交,引入新功能的通用函数或一组函数,然后在系列中稍后使用该功能。有时候,将其拆分成单独的提交并不值得。我通常尽量避免在提交中使用存根函数。

如果你正在寻找关于一个逻辑提交可能包含什么的灵感,Git 的历史是一个合理的地方。你无需理解详细的细节,只需要查看代码和提交的整体结构。

我有一些同事对他们的提交历史非常整洁,而其他人则不然。在我工作的地方,这不是优先考虑的问题,所以人们可以自由选择,只要他们提供一个有帮助的拉取请求消息。然而,如果你编写了好的提交消息,它们通常也会作为一个很好的拉取请求消息帮助你。

最终,正确的决策是你的团队可以达成一致意见的决策。Git 是一种多用途工具,可以成功适应许多工作流程。如果你的团队和工具支持多个提交,并且你认为这样更好,请去做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接