团队使用 Git 的 6 个最佳实践

通过使用这些 Git 协作策略更有效地工作。
137 位读者喜欢这篇文章。

Git 对于帮助小型团队管理其软件开发流程非常有用,但有些方法可以使其更有效。我发现了一些最佳实践,这些实践对我的团队很有帮助,尤其是在新团队成员加入且 Git 专业知识水平参差不齐的情况下。

为你的团队规范 Git 约定

每个人都应该遵循分支命名、标签和编码的标准约定。每个组织都有标准或最佳实践,并且互联网上可以免费获得许多建议。重要的是尽早选择合适的约定并作为一个团队遵守它。

此外,不同的团队成员对 Git 的专业知识水平也不同。你应该创建并维护一套基本的操作指南,用于执行遵循项目约定的常见 Git 操作。

正确合并更改

每个团队成员都应该在单独的功能分支上工作。但是,即使使用单独的分支,每个人最终都会修改一些公共文件。当将更改合并回 master 分支时,合并通常不会自动完成。可能需要人工干预来协调两位作者对同一文件所做的不同更改。这就是你必须学习如何处理 Git 合并技术的地方。

现代编辑器具有帮助处理 Git 合并冲突 的功能。它们在文件的每个部分中指示合并的各种选项,例如是保留你的更改、另一个分支的更改还是两者都保留。如果你的代码编辑器不支持此类功能,那么可能是时候选择其他代码编辑器了。

经常 rebase 你的功能分支

当你继续开发你的功能分支时,经常将其 rebase 到 master。这意味着定期执行以下步骤

git checkout master
git pull
git checkout feature-xyz  # name of your hypothetical feature branch
git rebase master  # may need to fix merge conflicts in feature-xyz

这些步骤 重写 你功能分支中的历史记录(这不是一件坏事)。首先,它使你的功能分支看起来像 master,其中包含截至当时的 master 的所有更新。然后,你对功能分支的所有提交都会在顶部重放,因此它们按顺序出现在 Git 日志中。你可能会遇到合并冲突,你需要沿途解决这些冲突,这可能是一个挑战。但是,这是处理合并冲突的最佳时机,因为它只会影响你的功能分支。

在你修复任何冲突并执行回归测试后,如果你准备好将你的功能合并回 master,请再次执行上述 rebase 步骤,然后执行合并

git checkout master
git pull
git merge feature-xyz

在此期间,如果其他人将与你的更改冲突的更改推送到 master,则 Git 合并将再次发生冲突。你需要解决它们并重复回归测试。

还有其他合并理念(例如,不使用 rebase 而仅使用 merge 来避免重写历史记录),其中一些理念甚至可能更易于使用。但是,我发现上述方法是一种干净可靠的策略。提交历史记录堆叠起来,成为一个有意义的功能序列。

使用“纯合并”策略(不定期 rebase,如上建议),master 分支中的历史记录将与所有正在并发开发的功能的提交交错在一起。这种混杂的历史记录更难审查。确切的提交时间通常不是那么重要。最好有一个更容易审查的历史记录。

在合并之前 squash 提交

在你的功能分支上工作时,即使是微小的更改也可以添加提交。但是,如果每个功能分支产生 50 个提交,随着功能的添加,master 分支中的提交数量可能会不必要地增长。一般来说,每个功能分支应该只向 master 添加一个或几个提交。为了实现这一点,squash 将多个提交合并为一个或几个提交,并为每个提交添加更详细的消息。这通常使用如下命令完成

git rebase -i HEAD~20  # look at up to 20 commits to consider squashing

当执行此操作时,会弹出一个编辑器,其中包含你可以通过多种方式操作的提交列表,包括 picksquashPick 提交意味着保留该提交消息。Squash 意味着将该提交的消息与前一个提交合并。使用这些和其他选项,你可以将提交消息合并为一个,并进行一些编辑和清理。这也是一个摆脱不重要的提交消息的机会(例如,关于修复拼写错误的提交消息)。

总之,保留与提交关联的所有操作,但在合并到 master 之前,合并和编辑关联的消息文本以提高清晰度。不要在 rebase 过程中意外删除提交。

在执行这样的 rebase 之后,我喜欢最后一次查看 git log 以进行最终编辑

git commit --amend

最后,由于分支的 Git 提交历史记录已被重写,因此强制更新到你的远程功能分支是必要的

git push -f

使用标签

在你完成测试并准备好从 master 分支部署软件后,或者如果你想出于任何其他原因将当前状态保留为一个重要的里程碑,请创建一个 Git 标签。虽然分支会累积与提交相对应的更改历史记录,但标签是分支在该时刻状态的快照。标签可以被认为是无历史记录的分支,也可以被认为是创建标签之前立即指向特定提交的命名指针。

配置控制是关于在各个里程碑处保留代码的状态。能够在任何里程碑处重现软件源代码,以便在必要时可以重建它是大多数项目中的一项要求。Git 标签为此类代码里程碑提供了唯一标识符。标记很简单

git tag milestone-id -m "short message saying what this milestone is about"
git push --tags   # don't forget to explicitly push the tag to the remote

考虑这样一种情况:将与给定 Git 标签对应的软件分发给客户,并且客户报告了一个问题。虽然存储库中的代码可能会继续演变,但通常有必要回到与 Git 标签对应的代码状态,以精确重现客户问题,从而创建错误修复。有时较新的代码可能已经修复了该问题,但并非总是如此。通常,你会检出特定的标签并从该标签创建一个分支

git checkout milestone-id        # checkout the tag that was distributed to the customer
git checkout -b new-branch-name  # create new branch to reproduce the bug

除此之外,如果它们对你的项目有益,请考虑使用带注释的标签和签名标签。

使软件可执行文件打印标签

在大多数嵌入式项目中,从软件构建创建的最终二进制文件具有固定的名称。与软件二进制文件对应的 Git 标签无法从其文件名中推断出来。在构建时将“标签嵌入”到软件中很有用,以便将任何未来的问题精确地关联到给定的构建。嵌入标签可以在构建过程中自动化。通常,git describe 生成的标签字符串会在代码编译之前插入到代码中,以便生成的执行文件在启动时打印标签字符串。当客户报告问题时,可以引导他们向你发送启动输出的副本。

结论

Git 是一个复杂的工具,需要时间才能掌握。使用这些实践可以帮助团队成功地使用 Git 进行协作,无论他们的专业知识水平如何。

接下来阅读什么
标签
User profile image.
Ravi 是无人机行业的软件工程师。他曾致力于各种问题,例如无人机传感器软件集成、DevOps、数字信号处理以及将机器学习应用于问题。他一直在寻找新的和有趣的软件工具来用于他的工作和爱好。他最喜欢的主题领域包括 Python、C#、Unity 和容器。

5 条评论

将 squash 作为“最佳实践”是一个非常危险的想法。你冒着丢失大量历史细节的风险 - 例如,添加新功能通常涉及现有代码的更改或重构;通常是由其他团队成员编写的代码,他们可能需要在某个时候“git blame”以查看解释,这应该在你的日志中记录受影响的行。(绝对的最佳实践!)

另一个最佳实践是在你代码的各个领域工作时修复和改进你发现的东西 - 这应该在单独的提交中完成,再次是为了让你的团队成员意识到不仅“什么”,而且“为什么”你更改了某些东西。squash 提交往往会变成一个很大的“什么”球,而没有“为什么”,因此这真的不能作为默认值。

将 rebase 作为最佳实践是我一直想做但从未能够做到的事情,因为它需要强制推送的权限 - 因此也真的只在你是一个人在特定分支上工作时才有效。它作为与 squash 结合的最佳实践也没有真正的意义,因为如果你正在 squash,你的拉取请求无论如何都是单个提交。

在教授这些东西时,我们不能过于概括 - 我认为,它应该作为在某些特定条件下应用的技术来教授,而不应作为最佳实践强加给任何人;这样做有“货物崇拜”的风险,即你经验不足的团队成员正在应用先进技术,将它们作为“最佳实践”教给其他团队成员,最终没有人完全理解他们为什么要做他们所做的事情,这可能会给整个团队带来严重的问题。

感谢提出一些重要的讨论点!

本文中讨论的工作流程,特别是关于 rebase 和 squash 的工作流程,适用于每个开发人员在单独的功能分支上工作并具有功能分支的强制推送权限的用例。在你多人贡献一个功能分支的 Git 用法中,我同意 squash 和 rebase 的这种组合将不适用。

我同意,与重构现有代码或为方便新功能而进行的其他重大代码更改相关的提交通常不应与,例如,与为该功能添加的新文件相关的提交一起 squash。

通常,每个功能分支在 squash 后都会产生一些提交。其中一些将归因于你提到的事情(例如,重构现有代码)。还有一两个提交将是将与新功能相关的新文件相关的提交 squash 在一起的结果。

我不确定你关于拉取请求是单个提交的评论。拉取请求可以为功能分支中的几个提交提交。批准者然后可以执行合并提交,该合并提交将包括多个拉取请求提交,以及表示从功能分支合并拉取请求的附加提交。

我同意你关于我们不应该过于概括等的担忧。实际上,解释特定技术的目的是新团队成员入职培训的一部分,并理解可能需要一些经验才能理解这些概念。(例如,我认为人们必须在错误修复期间与一些 Git 日志作斗争,才能真正体会到拥有良好、有序的 Git 提交历史记录的价值。)我想我只是在这种情况下将“最佳实践”视为 Git 的这种常见用例的良好工作流程。此工作流程当然不适用于每个基于 Git 的项目。

回复 ,作者:Rasmus Schultz (未验证)

好文章,我真的很喜欢。我最喜欢的是“经常 rebase 你的功能分支”

不错 ...

另外:请重命名你的默认分支。

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.