养成良好的 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 的具体流程会因所使用的版本控制托管平台而有所不同,但基本概念是相同的。

首先,你应该从代码库中检出主分支(通常是 main 或 master)。然后运行 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 或其他版本控制系统的电子邮件通知过滤到一个文件夹里,由于仓库、提交、分支等的更新量太大,通常很少查看这些通知。

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