养成良好的 Git 使用习惯

养成良好的 Git 使用习惯

本文将介绍一些 Git 的最佳实践,帮助你更好地使用 Git。

提交信息

提交信息是 Git 中最重要的一环。一个好的提交信息可以让你的团队更好地了解你的提交。一个好的提交信息应该包含以下内容:

  • 提交的目的
  • 提交的内容
  • 提交的原因

虽然包含的内容还挺多,但是请尽量控制在 50 个字符以内。这样可以让你的提交信息更加简洁,也更容易阅读。 如果一定要添加更多的解释,请用足够简短的语言来解释,然后换行,用更详细的语言来解释。

分支管理

分支是 Git 中最重要的概念之一。分支可以让你在不影响主分支的情况下进行开发。在开发时,你应该遵循以下原则:

  • 主分支是稳定的,不应该直接在主分支上进行开发。
  • 每个功能应该在一个独立的分支上进行开发,这样可以更好地管理代码。
  • 开发完成后,应该将分支合并到主分支上。

这是我在前面的教程中一定要求大家在语义分支上进行开发的原因。这样可以更好地管理代码,也更容易回滚。

代码审查

代码审查是一个非常重要的环节。代码审查可以让你的代码更加稳定,也可以让你的团队更好地了解你的代码。在代码审查时,你应该遵循以下原则:

  • 代码审查应该在开发完成后进行。
  • 代码审查应该在一个独立的分支上进行。
  • 代码审查应该由其他人进行,这样可以更好地发现问题。最好是一群擅长不同领域的人进行代码审查。

合并分支

通常来说,在本地合并分支时,应该使用 rebase 来合并分支。这样可以让你的提交历史更加清晰,避免出现不必要的合并提交。

在 Pull Request 合并时,应该使用merge来合并分支。这样可以让你的提交历史更加清晰,也更容易回滚。

Commit 时机

很多新手在使用 Git 时,要么提交太多次。这样会让你的提交历史变得混乱,也会让你的团队很难理解你的提交。要么提交太少,这样会让你的提交历史变得不够详细,也会让你的团队很难理解你的提交。

一个好的提交时机是在你完成一个功能后提交。这样可以让你的提交历史更加清晰,也更容易回滚。

要理解,commit 的本质是patch,当你的 commit 较为复杂时,就不容易patch apply。所以,尽量保持 commit 的简单,但是简单的前提是保证一项功能的完整性。

Git 使用最佳实践

注:以下内容翻译自Git Best Practices – How to Write Meaningful Commits, Effective Pull Requests, and Code Reviews

作者: Grant Riordan

编写有意义的提交信息

在提交代码时,编写有用的提交信息是很有帮助的。以下是一些提示和最佳实践,帮助你做到这一点。

使用祈使句

在提交信息前缀中使用祈使句,例如:fix、refactor、add 和 remove。

这应该是你提交信息的第一个单词,因为它可以很容易地告诉你的同事这个提交的目的:

  • “If applied, this code will…”

并告知其他开发人员它将做什么,例如:

  • If applied, this code will fix issue with login button not showing

保持简洁

你不是在写独白,所以保持简洁。一般来说,提交信息不应超过 50 个字符。

站在开发人员或审查者的角度思考。如果你在查看这个仓库的 Git 日志时,你会想知道什么?

  • 你完成了什么工作?
  • 你为什么这样做?
  • 它对代码库有什么影响?

以下是一个简洁但信息丰富的提交信息示例:

fix issue with login button not showing

保持简洁但是有意义

在你的提交中,你可以包含提交描述,允许我们添加更多的细节/上下文说明你做了什么。

在提交信息下方添加一个空行,并在第 3 行开始编写描述。它看起来像这样:

fix issue with login buttton not showing

- update login form validation
- update login styling for showing the button

现在,当其他开发人员查看提交历史,或回滚代码时,他们会更清楚地了解会发生什么,以及是否会产生任何副作用。

反面教材

  1. fixed bug – 没有提到具体修复了什么 bug,因此它对 git 历史/日志没有任何价值。这将使审查以前的提交变得极其困难和痛苦。作为开发人员,你必须打开每个这样的提交才能理解它实际上在做什么。

  2. refactored due to PR comments – 此信息没有提供有关更改的任何信息。我们必须追踪 Pull Request 以收集有关所做更改的任何上下文,或者再次打开提交。

  3. fixing previous commit – 同样,缺乏上下文

  4. made tests pass – 更新了哪个测试文件?你至少应该提供已修复的测试名称或区域。 所有这些都是不良提交信息的示例,因为它们含糊不清、缺乏信息和上下文。它们迫使团队成员做更多的工作来理解发生了什么,这是任何团队都不能接受的。

如何制定提交策略

你可能认为提交代码就是简单地提交和推送代码。但实际上,这里面还有一些细微的差别。

让我们来谈谈如何制定一个有用的提交策略,以保持一致性并做出有价值的提交。

进行小而具体的提交

小规模的提交使得在出现问题时,能够更容易地将代码恢复到之前的状态。如果你的提交影响了太多的区域,那么回退可能意味着丢失大量的代码。

对于代码审查者来说,如果提交只与一个特定的目的相关,他们会更容易理解代码的作用。

让我们来看一个实际的例子,看看这是如何运作的。首先,我们需要添加相关的文件更改。我们可以通过运行 git status 来查看当前分支中哪些文件已被更改。

On branch: master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .DS_Store
        login.test.ts
        login.ts
        product.ts
        registeration.test.ts
        registeration.ts
        validation.test.ts
        validation.ts

no changes added to commit (use "git add" and/or "git commit -a")

如你所见,有多个文件已在项目中被更改或添加。然而,这些文件分别属于项目的不同部分。遵循保持提交小而相关的黄金法则,让我们看看如何将其付诸实践。

我们可以使用 git add 命令加上文件名,仅提交那些相关的文件。具体操作是使用 git add 命令,然后逐一添加我们希望提交的文件名,例如:

git add login.test.ts login.ts

如果我们现在检查 git status,就会看到这两个已暂存的文件:

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   login.test.ts
        new file:   login.ts

我们已经暂存了这些文件,现在要创建提交。一如既往,我们将使用 git commit,这会在 VS Code 中打开 git 编辑器(因为我们之前已经这样设置过)。如果你跳过了这一步,提交信息会在你首选的编辑器中打开。

接下来,我们添加一个描述更改的提交消息:

Fix issue with login button not showing

这样就完成了一个小而相关的文件提交。提交消息明确地告诉我们进行了什么更改、问题出在哪里,并提供了一些关于问题的小背景信息。

反面教材

不良提交示例

既然我们已经成功完成了一个良好的提交,让我们来看看一个不良提交的例子:

假设我们已经完成了所有工作,开发者使用 git add -A 命令一次性暂存了所有更改或添加的文件。

多个不相关文件被暂存以提交的示例

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .DS_Store
        new file:   product.ts
        new file:   registeration.test.ts
        new file:   registeration.ts
        new file:   validation.test.ts
        new file:   validation.ts

然后,他们使用一行命令创建了提交消息:

git commit -m 'Updated various areas such as validation, registration and products pages'
为什么这是一个糟糕的提交?

首先,这个提交包含了太多更改。过多的文件意味着如果我们需要回退验证部分的更改时,将无法只回退那一部分。我们不得不回退整个提交,从而丢失产品和注册部分的更改。

其次,提交消息过于冗长。我们可以去掉诸如“various areas such as”这样的无意义的词语。这些词语对提交消息没有任何贡献,还占用了本可以用于更多背景信息的字符数。

此外,我们没有使用前面提到的祈使语态。我们应该将“Updated”改为“Update”。

如何创建高效的 Pull Requests

决定何时推送

推送是将你的提交发送到服务器/远程仓库,以准备创建 Pull Request (PR)的过程。我建议在当前功能或修复完成后立即进行推送。

此外,保持你的 PR 小而精简,仅包含相关的提交是个好主意。例如,如果你有以下提交:

  • 添加新产品搜索组件
  • 为产品搜索组件添加单元测试
  • 添加产品搜索组件的文档

由于所有这些提交都与同一组件相关,建议将它们合并到一个 PR 中。

而像这样的提交:

  • 修复登录屏幕中的错误
  • 为提高性能重构注册页面
  • 更新登录表单的验证测试
  • 更新登录测试以支持忘记密码功能
  • 更新产品搜索组件的单元测试

不应放在同一个 PR 中,因为这些提交涉及太多不同的内容。这些提交应该根据相关性分组为多个 PR。

如果这是一个分支的 Git 日志,你将无法仅使用相关文件创建 Pull Request ,因为提交的顺序已经固定,你不能简单地告诉 Git 你希望将第 1、3 和 4 个提交放入这个 PR 中。

保持小规模

记住——就像你的提交一样,保持 PR 小而精简。没有人愿意处理一个包含 50 多个文件的 Pull Request 。这样做只会让你的审查陷入常见的“看起来没问题”的陷阱。

当你创建一个大型 PR 时,实际上是在传达“我不想仔细检查所有这些文件,但粗略看了一下,好像还行”的信息。相比之下,一个小型 PR 则更容易得到确切的审查意见。

有时,大型 Pull Request 是不可避免的,比如在更新基础功能时。然而,你应该尽量考虑如何减少对其他开发人员的影响。

如何为代码审查做好分支准备

创建 Pull Request 的具体流程会因所使用的版本控制托管平台而有所不同,但基本概念是相同的。

首先,你应该从代码库中检出主分支(通常是 mainmaster)。然后运行 git pull,这会将主分支的最新代码拉取到你的本地开发系统中。

完成后,你可以使用 git checkout 命令切换回你自己的分支,例如:

git checkout login-fixes

现在,我们需要将主分支的代码合并到你的分支中。可以使用 git merge 命令来实现这一点:

git merge main

如果存在更改,即从主分支拉取的文件中有更新,你需要创建一个“合并提交”。这是在你的分支上包含合并更改的另一个提交。

只需创建另一个提交,并附上解释你已经从主分支合并的消息,例如:

git commit -m 'Merge main into login-fixes'

最后,使用 git push 将你的更改推送回远程服务器。

PR 代码审查

审查 PR 时需要注意什么

在审查 PR 时,首先要退一步,考虑良好代码审查的关键要素。以下是一些需要考虑的要点:

  1. 代码是否遵循团队的编码规范? 确保提交的代码符合团队的编码标准和惯例。这是维护代码库一致性的重要步骤。

  2. 代码是否达到了预期目标/验收标准? 审查代码是否实现了它所承诺的功能或修复了特定的问题,并符合相关的验收标准。

  3. 代码是否易读易懂? 代码是否易于理解,而无需大量注释或文档?这点非常重要,尤其是当函数和变量名称具有描述性时,可以大大提高代码的可读性。

  4. 代码是否需要重构? 从安全性、性能或可读性角度考虑,代码是否需要重构?通过重构,代码可以变得更简洁、更高效。

  5. 代码是否遵循简单的设计模式/原则? 例如单一职责原则、抽象、封装等。如果没有遵循,可以提出建议,或者向不熟悉这些概念的开发者解释其含义及其带来的好处。

  6. 是否存在“magic 数字/字符串”? 检查代码中是否有未命名的常量或字符串,考虑将其替换为命名常量或变量,以提高代码的可维护性。

及时审查 PR

虽然不必马上查看 PR,但也不要让作者久等。这个 PR 可能会阻碍后续工作,或者它可能很重要(如果是这样,作者应该明确说明)。

尽量保持讨论和 PR 评论的顺畅。如果方便的话,可以通过电话(如果是远程工作)或在办公室里一起审查 PR,这可能会加快流程,减少来回等待的时间。

尽管如此,也不要急于完成代码审查。要仔细、认真地阅读每个文件和更改。我建议你检出包含更改的分支,查看整个项目,而不仅仅是更改的几行代码。

很多时候,仅仅查看一两行代码的更改,你可能无法准确理解代码的意图。但如果查看整个文件,你可以更好地理解代码的整体逻辑。

如果你使用的是 VS Code 和 GitHub,可以利用它们的扩展功能,在 VS Code 内部查看 PR、发表评论,并同时检出 PR 分支。

记住我们都是人

记住,我们都是人,编写代码时人们经常会犯错误,也可能忽略一些细节。

并不是每个人的编码方式都和你一样,所以不要仅仅因为别人的做法和你的不同就要求修改。这并不意味着他们做错了,也不意味着你的方式就是最好的。

清晰描述修改意见,谨慎措辞

拉取请求(PR)不是考试,也不是你严厉批评别人工作的机会。这是一个学习的机会,也是确保最佳代码进入主分支的机会。重点在于代码质量以及代码是否符合验收标准。

在提出建议时,考虑一下你使用的语言。PR 评论与 git 提交消息恰恰相反。在 PR 评论中,我们不再使用祈使语态。不要命令对方做出更改,而是使用虚拟语气来提出更柔和的建议。

由于你是在批评别人可能付出了很多努力的工作,使用一些委婉的表达方式,比如:

  • “如果是我,我会将这个 if 语句改为 switch case 语句,因为它更易读。”
  • “或许可以考虑将这个变量重命名为一个更直观的名称,例如 {alternative},这样可以更容易理解它的作用。”

如上所述,尝试添加你提出修改建议的原因。这样会使建议更有影响力,并让作者思考是否应该做出更改,或者引发讨论以达成折中方案。

提供改进建议

大多数 Git 系统允许你点击需要更改的代码行并添加评论,这样更容易指定你希望修改的确切代码行。

像 GitHub 这样的托管平台有“建议”功能,允许你在评论中直接添加代码建议,这些建议可以在 PR 中立即接受并提交。

如果没有这个功能,确保你请求的内容清晰简明。你甚至可以在评论中重写或写出你的建议,例如:

“或许可以考虑将这个 if/else 语句改为三元表达式,如下所示:”

var backgroundColor = isError ? 'red' : 'blue'

这样可以使建议更加明确,并加快重新编写的过程(通过复制粘贴)。

不要害怕为你的代码辩护

记住,PR 是一种讨论。这是一个双向的过程,给你机会为你的代码辩护,并用更多的背景信息解释你的想法。

尽管代码可能看起来不完美,但可能有原因。可能存在你无法控制的因素,迫使你以某种方式编写代码。

不要害怕提出反驳意见,但要准备好合理的理由,尤其是在你确实相信你的解决方案是最佳的情况下。

传达 PR 已被批准

如今,许多人会将 GitHub 或其他版本控制系统的电子邮件通知过滤到一个文件夹里,由于仓库、提交、分支等的更新量太大,通常很少查看这些通知。

为了加快进程,并使作者的体验更愉快,可以简单地给他们发个消息。许多公司现在都有即时消息服务,为什么不利用这一点呢?