本文是我们“高级 Git”系列的一部分。 请务必关注 Tower 的 Twitter 或注册 Tower 时事通讯 以了解下一篇文章的信息!
Git 中的提交可以是以下两种情况之一
- 它可以是来自各种主题的更改的杂乱组合:一些用于错误修复的代码行、重写旧模块的尝试以及几个用于全新功能的新文件。
- 或者,通过一点小心,它可以帮助我们掌握事态。 它可以成为属于一个且仅一个主题的相关更改的容器,从而使我们更容易理解发生了什么。
在这篇文章中,我们讨论了产生后一种提交类型需要什么,或者换句话说:“完美”的提交。
高级 Git 系列
- 第 1 部分: 在 Git 中创建完美的提交(您在此处!)
- 第 2 部分: Git 中的分支策略
- 第 3 部分: 通过拉取请求实现更好的协作
- 第 4 部分: 合并冲突
- 第 5 部分: 变基与合并
- 第 6 部分: 交互式变基
- 第 7 部分: 在 Git 中挑选提交
- 第 8 部分: 使用 Reflog 恢复丢失的提交
为什么整洁且细粒度的提交很重要
是否真的有必要以谨慎、周到的方式编写提交? 我们能否将 Git 视为一个无聊的备份系统? 让我们再次回顾一下上面的示例。
如果我们遵循第一条路径——在每次发生更改时都将更改塞进提交中——提交就会失去大部分价值。 一个提交与下一个提交之间的分离变得随意:似乎没有理由将更改放入一个提交而不是另一个提交中。 稍后查看这些提交,例如,当您的同事试图理解该修订版中发生了什么时,就像翻阅每个家庭都拥有的“杂物抽屉”一样:这里面有所有在其他地方找不到的东西,从蜡笔到图钉和收据。 在这些抽屉里找东西非常困难!

遵循第二条路径——我们只将属于同一提交的内容(即更改)放入同一提交中——需要更多的计划和纪律。 但最终,您和您的团队会获得非常有价值的东西:一个干净的提交历史! 这些提交可以帮助您了解发生了什么。 它们有助于以易于理解的方式解释所做的复杂更改。

我们如何创建更好的提交?
编写更好的提交
一个概念对于在 Git 中编写更好的提交至关重要:暂存区。
暂存区正是为此目的而创建的:允许开发人员以非常细粒度的方式选择应包含在下一次提交中的更改。 而且,与其他版本控制系统不同,Git 强制您使用此暂存区。
但是,不幸的是,仍然很容易忽略暂存区的整理效果:一个简单的 git add .
将获取所有当前的本地更改,并将其标记为下一次提交。
确实,这有时可能是一种非常有用且有效的方法。 但很多时候,我们最好停下来思考一下,我们所有的更改是否确实都与同一个主题有关。 或者两个或三个单独的提交是否可能是一个更好的选择。
在大多数情况下,保持提交比更大的提交小得多是有意义的。 它们专注于单个主题(而不是两个、三个或四个),因此往往更易于阅读。
暂存区允许我们仔细挑选应包含在下一次提交中的每个更改:
$ git add file1.ext file2.ext
这只会将这两个文件标记为下一次提交,并将其他更改保留在以后的提交或进一步编辑中。
这种暂停并刻意选择什么应该进入下一次提交的简单行为意义重大。 但我们还可以做得更精确。 因为有时,即使单个文件中的更改也属于多个主题。
让我们看一个真实的例子,并查看“index.html”文件中的确切更改。 我们可以使用“git diff”命令或像Tower这样的 Git 桌面 GUI

现在,我们可以将 -p
选项添加到 git add
$ git add -p index.html
我们指示 Git 在“补丁”级别遍历此文件:Git 手把手地引导我们遍历此文件中的所有更改。 并且它会询问我们,对于每个块,我们是否要将其添加到暂存区。

通过为第一个块键入 [Y]
(表示“是”)并为第二个块键入 [N]
(表示“否”),我们可以将此文件中的更改的第一部分包含在下一次提交中,但将其他更改保留在以后或进行更多编辑。
结果如何? 一个更细粒度、更精确的提交,专注于单个主题。
测试您的代码
由于我们在这里讨论的是“完美的提交”,因此我们不能忽略测试主题。 您“测试”代码的确切方式当然可能会有所不同,但测试很重要这一概念并不新鲜。 事实上,许多团队拒绝将未经适当测试的代码视为已完成的代码。
如果您仍然对是否应该测试代码犹豫不决,让我们消除一些关于测试的神话
- “测试被高估了”:事实是,测试可以帮助您更快地发现错误。 最重要的是,它们可以帮助您在某些内容进入生产环境之前发现错误——因为这是错误造成最大伤害的时候。 而尽早发现错误,毫不夸张地说,是无价的!
- “测试会浪费宝贵的时间”:一段时间后,您会发现编写良好的测试可以让您更快地编写代码。 您会花费更少的时间来查找错误,并且会发现,更常见的是,结构良好的测试也会为您实际的实现做好准备。
- “测试很复杂”:虽然这在几年前可能是一个论点,但现在并非如此。 大多数专业的编程框架和语言都提供了广泛的支持来设置、编写和管理测试。
总而言之,将测试添加到您的开发习惯中几乎可以保证使您的代码库更加健壮。 同时,它们还能帮助您成为一名更好的程序员。
有价值的提交信息
使用 Git 进行版本控制并不是一种花哨的备份代码方式。 而且,正如我们已经讨论过的,提交不是任意更改的转储。 提交的存在是为了帮助您和您的团队成员了解项目中发生了什么。 而一个好的提交信息对于确保这一点大有帮助。
但是,什么构成了一个好的提交信息?
- 一个简短且简洁的主题行,总结了更改
- 一个描述性的消息正文,解释了最重要的内容(并尽可能简洁)
让我们从主题行开始:目标是获得发生情况的简要摘要。 当然,简洁是一个相对的概念; 但一般的经验法则是(理想情况下)将主题保持在 50 个字符以内。 顺便说一句,如果您发现自己难以想出一个简短的内容,这可能表明提交处理了太多主题! 值得再次查看一下,看看您是否需要将其拆分为多个单独的主题。
如果您在主题后面加上换行符和一个额外的空行,Git 会理解以下文本是消息的“正文”。 在这里,您有更多空间来描述发生了什么。 记住以下问题会有所帮助,您的正文应旨在回答这些问题
- 此提交对您的项目进行了哪些更改?
- 进行此更改的原因是什么?
- 是否有任何需要注意的事项? 其他人需要了解有关这些更改的任何信息?
如果您在编写提交信息正文时牢记这些问题,您很可能会产生对发生情况的有用描述。 最终,这会在尝试理解此提交时使您的同事(以及一段时间后的您)受益。
除了我刚才描述的关于提交信息内容的规则外,许多团队也关心格式:就字符限制、软或硬换行等达成一致,都有助于在团队内创建更好的提交。
为了更容易遵守此类规则,我们最近在我们制作的 Git 桌面 GUI Tower中添加了一些功能:例如,您现在可以根据自己的喜好配置字符计数或自动换行。

优秀的代码库源于优秀的提交
任何开发者都会承认他们想要一个优秀的代码库。但要实现这一崇高目标,只有一个途径:持续创建优秀的提交!我希望我已经证明了 (a) 追求这个目标绝对值得,并且 (b) 实现它并不那么难。
如果你想深入了解高级 Git 工具,请随时查看我的(免费!)“高级 Git 工具包”:它包含一系列关于分支策略、交互式变基、Reflog、子模块等等主题的短视频。
祝你创建出色的提交!
高级 Git 系列
- 第 1 部分: 在 Git 中创建完美的提交(您在此处!)
- 第 2 部分: Git 中的分支策略
- 第 3 部分: 通过拉取请求实现更好的协作
- 第 4 部分: 合并冲突
- 第 5 部分: 变基与合并
- 第 6 部分: 交互式变基
- 第 7 部分: 在 Git 中挑选提交
- 第 8 部分: 使用 Reflog 恢复丢失的提交
您提供的文章内容很棒,解决了困扰每个开发者日常生活的许多痛点。精彩的文章,继续努力!
我完全同意。管理良好的 Git 提交可以在出现问题并需要修复特定问题时挽救企业。
很棒的文章。但是,我想到以下问题:需要深入研究提交历史以了解项目状况的频率有多高?我认为非常罕见,如果不是接近于从未。Pull Request 描述了项目中的“变更单元”,从这个角度来看,一个 PR 是否只有一个提交或 50 个提交并不重要。
最重要的是,主题行通常用于 CI(例如,它必须遵循某种模式,例如
<YourTicketingSystemPrefix><TicketNumber>
,例如SW-1234
)。然后,此类模式通常由工单系统(Jira、YouTrack 等)用于自动更新相关工单。然后,如果开发人员仅仅花费 5 分钟来编写提交描述,并且每天进行 10-15 次提交,那么每天至少会花费一个小时来编写良好的提交描述。这是时间上的明智之举吗?它能为最终结果增加价值吗?我认为不能。为什么???因为很少(如果有的话)会深入研究提交历史,尤其是阅读描述来弄清项目的情况。
这将很大程度上取决于项目的规模/复杂性、工作流程、变更频率、特性/PR/MR 等的范围。仅供参考,虽然非常流行,但并非所有项目都使用 PR 工作流程。
即使对于那些使用 PR 的项目,正如您所指出的,PR 由提交组成。提交是变更的原子单元,即使在 PR 中也是如此。PR 或特性分支越大,精心策划的提交对于理解变更集就越重要。我们之中那些经常需要维护、审查和/或追溯性调查对代码库贡献的人感谢您提供专注、简洁、精心策划的提交。
但精心策划的提交不仅仅是为了维护人员。结构化、专注的提交使开发人员能够在动态项目环境中灵活地发展他们的工作。我逐渐认识到 Git 不仅仅是一个版本控制/历史记录工具,而是一个用于切分和整理代码的工具。我对精心策划我的提交投入越多,我就越容易在快速变化的代码库中挑选、变基以及以其他方式重构我的工作(以及其他人的工作)。当然,这些通常只有当您与其他开发人员密切合作(在相同的特性/文件上)时才会遇到的问题。
构建专注的提交并编写良好的提交信息是一种上下文文档的形式,在代码注释、工单/问题跟踪等方面具有重要的位置(和平衡)。如果一个提交信息需要 5 分钟来撰写,那它可能过于冗长了。
我只是偶然路过(手机上看似随机的推荐),但我很高兴偶然看到了。很棒的文章
我刚刚升级了!
正在等待发布其余内容。