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