使用 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 而只使用合并来避免重写历史记录),其中一些甚至可能更易于使用。 但是,我发现上述方法是一种干净且可靠的策略。 提交历史记录被堆叠为有意义的功能序列。

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

在合并之前 squash 提交

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

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

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

总而言之,保留与提交关联的所有操作,但在合并到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 作为最佳实践是我一直想做但从未做过的事情,因为它需要强制推送的权限 - 因此实际上只有在您是唯一在特定分支上工作的人员时才有效。 它与 squashing 结合作为最佳实践也没有多大意义,因为如果您正在 squashing,那么您的 pull request 无论如何都是一个单独的提交。

在教授这些内容时,我们不能过度概括。我认为,应该将它们作为在特定条件下应用的技术来教授,不应该强加给任何人作为最佳实践。这样做存在的风险是“迷信式编程”,即缺乏经验的团队成员应用高级技术,并将它们作为“最佳实践”教给其他团队成员,最终没有人完全理解他们这样做的原因,这可能会给整个团队带来严重的问题。

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

本文讨论的工作流程,特别是关于变基(rebasing)和压缩(squashing),适用于每个开发人员在单独的功能分支上工作并拥有功能分支强制推送权限的用例。在您的 Git 用法中,如果一个功能分支有多个贡献者,我同意这种压缩和变基的组合将不适用。

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

通常,每个功能分支在压缩后会产生少量的提交。其中一些将是由于您提到的原因(例如,重构现有代码)。还有一两个提交将是压缩与新功能相关的新文件相关的提交的结果。

我不确定您关于拉取请求是单个提交的评论。可以为功能分支中的少量提交提交拉取请求。审批者然后可以执行合并提交,该提交将包括多个拉取请求提交,以及代表从功能分支合并拉取请求的额外提交。

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

回复

不错的帖子,我真的很喜欢。我最喜欢的是“经常对你的功能分支进行变基”。

不错...

还有:请重命名你的默认分支。

Creative Commons License本作品基于 Creative Commons Attribution-Share Alike 4.0 International License 协议进行许可。
© . All rights reserved.