简体中文 ▾ 主题 ▾ 最新版本 ▾ gitworkflows 最后更新于 2.35.0

名称

gitworkflows - Git 推荐工作流概览

概要

git *

描述

本文档旨在记录并说明 git.git 本身所使用的一些工作流要素。许多想法普遍适用,尽管对于参与人数较少的较小项目,通常无需采用完整的工作流。

我们制定了一套规则供快速参考,正文部分则试图说明每一条规则背后的动机。不必总是死板地照搬;相比于此类手册,你应该更看重行动背后的正当理由。

分离变更

作为一般规则,你应该尝试将变更拆分为小的逻辑步骤,并提交每一个步骤。它们应该是连贯的,独立于后续的任何提交工作,能够通过测试套件,等等。这会使审查过程变得容易得多,并使历史记录对于后续的检查和分析更有价值,例如使用 git-blame[1]git-bisect[1]

为了实现这一点,请从一开始就尝试将工作拆分为小步骤。将几个提交压缩在一起总是比将一个巨大的提交拆分成多个要容易得多。不要害怕在此过程中提交太小或不够完美。你以后总是可以返回,并在发布它们之前使用 git rebase --interactive 编辑这些提交。你可以使用 git stash push --keep-index 在不影响其他未提交变更的情况下运行测试套件;请参阅 git-stash[1] 的“示例”部分。

管理分支

有两种主要工具可用于将变更从一个分支引入到另一个分支:git-merge[1]git-cherry-pick[1]

合并(Merge)有很多优点,因此我们尝试尽可能多地只使用合并来解决问题。挑拣(Cherry-picking)偶尔仍然有用;请参阅下文的“向上合并”以获取示例。

最重要的是,合并是在分支级别工作的,而挑拣是在提交级别工作的。这意味着合并可以轻松地携带 1 个、10 个或 1000 个提交的变更,这反过来意味着工作流可以更好地扩展以适应大量的贡献者(和贡献)。合并也更容易理解,因为合并提交是一个“承诺”,即其所有父提交中的所有变更现在都已包含在内。

当然,这需要权衡:合并需要更谨慎的分支管理。以下小节讨论了重点内容。

演进(Graduation)

当一个给定的功能从实验阶段进入稳定阶段时,它也会在软件相应的分支之间“演进”。git.git 使用以下集成分支

  • maint 跟踪应进入下一次“维护版本发布”的提交,即对上一个发布稳定版本的更新;

  • master 跟踪应进入下一次发布版本的提交;

  • next 旨在作为测试分支,用于测试那些为 master 准备的功能的稳定性。

还有第四个官方分支,其使用方式略有不同

  • seen(维护者看到的补丁)是一个集成分支,用于那些尚未完全准备好被纳入的分支(请参阅下文的“集成分支”)。

这四个分支中的每一个通常都是其上方分支的直接后代。

从概念上讲,功能进入一个不稳定分支(通常是 nextseen),一旦被认为足够稳定,就会“演进”到 master 以用于下一次发布。

向上合并

然而,上述讨论的“向下演进”不能通过实际的向下合并来完成,因为那会合并不稳定分支上的所有变更到稳定分支中。因此,遵循以下规则

规则:向上合并

始终将修复提交到需要它们的最旧的受支持分支。然后(定期)将集成分支彼此向上合并。

这提供了一个非常受控的修复流程。如果你发现你已将修复应用到了例如 master,但该修复在 maint 中也需要,则需要向下挑拣(使用 git-cherry-pick[1])它。这种情况偶尔会发生,除非你非常频繁地这样做,否则不必担心。

主题分支

任何非平凡的功能都需要多个补丁来实现,并且在其生命周期内可能会获得额外的错误修复或改进。

直接在集成分支上提交所有内容会导致许多问题:错误的提交无法撤消,因此必须逐个恢复,这会造成混乱的历史记录,并且在忘记恢复一部分相关变更时会产生进一步的错误潜力。并行工作会混合变更,造成进一步的混乱。

使用“主题分支”解决了这些问题。名称本身就很好理解,但有一个源自上述“向上合并”规则的注意事项

规则:主题分支

为每个主题(功能、错误修复等)创建一个侧分支。从你最终想要将其合并入的最旧的集成分支中派生出来。

这样可以非常自然地完成许多事情

  • 要将功能/错误修复放入集成分支,只需将其合并即可。如果主题在此期间有了进一步的发展,请再次合并。(请注意,不一定要先将其合并到最旧的集成分支。例如,你可以先将错误修复合并到 next,给它一些测试时间,并在知道它稳定后将其合并到 maint。)

  • 如果你发现需要来自 other 分支的新功能来继续处理你的主题,请将 other 合并到 topic。(但是,不要“习惯性”地这样做,请见下文。)

  • 如果你发现是从错误的分支派生的,并且想将其“移回过去”,请使用 git-rebase[1]

请注意,最后一点与前两点冲突:已合并到其他地方的主题不应进行变基。请参阅 git-rebase[1] 中关于“从上游变基中恢复”的部分。

我们应该指出,“习惯性地”(没有真正理由地定期)将集成分支合并到你的主题中——或者推而广之,定期将任何上游内容合并到任何下游内容——是不受欢迎的

规则:仅在定义明确的点合并到下游

除非有正当理由,否则不要合并到下游:上游 API 变更影响了你的分支;你的分支不再能干净地合并到上游;等等。

否则,被合并到的主题会突然包含多个(非单一分离的)变更。由此产生的许多小合并将极大地扰乱历史记录。任何后来调查文件历史的人都必须查明该合并是否影响了开发中的主题。甚至上游也可能无意中被合并到一个“更稳定”的分支中。等等。

抛弃式集成

如果你遵循了上一段的内容,你现在将拥有许多小的主题分支,并且偶尔会想知道它们是如何相互作用的。也许合并它们的结果甚至无法工作?但另一方面,我们想避免将它们合并到任何“稳定”的地方,因为这样的合并无法轻易撤消。

解决方案当然是进行一次我们可以撤消的合并:合并到一个抛弃式分支中。

规则:抛弃式集成分支

为了测试多个主题的交互,请将它们合并到一个抛弃式分支中。你绝不能基于这样的分支进行任何工作!

如果你(非常)清楚地表明此分支将在测试后立即删除,你甚至可以发布此分支,例如,让测试人员有机会使用它,或让其他开发人员有机会查看他们正在进行的工作是否兼容。git.git 有一个这样的官方抛弃式集成分支,称为 seen

发布版本的分支管理

假设你正在使用上述讨论的合并方法,在发布你的项目时,你需要做一些额外的工作。

功能发布版本是从 master 分支创建的,因为 master 跟踪应进入下一次功能发布的提交。

master 分支应该是 maint 的超集。如果不满足此条件,则 maint 包含一些未包含在 master 中的提交。因此,这些提交所代表的修复将不会包含在你的功能发布中。

要验证 master 是否确实是 maint 的超集,请使用 git log

方法:验证 master 是否为 maint 的超集

git log master..maint

此命令不应列出任何提交。否则,检出 master 并将 maint 合并入其中。

现在你可以继续进行功能发布。在 master 的尖端应用一个标签,指明发布版本

方法:发布打标签

git tag -s -m "Git X.Y.Z" vX.Y.Z master

你需要将新标签推送到公共 Git 服务器(请参阅下文的“分布式工作流”)。这使得标签对跟踪你项目的其他人可用。推送还可以触发 post-update 钩子来执行与发布相关的项目,例如构建发布压缩包和预格式化的文档页面。

同样,对于维护版本发布,maint 跟踪要发布的提交。因此,在上述步骤中,只需对 maint 而不是 master 进行打标签和推送。

功能发布后的维护分支管理

在功能发布之后,你需要管理你的维护分支。

首先,如果你希望继续为最近一次发布之前的发布版本发布维护修复,那么你必须创建另一个分支来跟踪该先前发布的提交。

为此,当前的维护分支被复制到另一个以先前发布版本号命名的分支(例如 maint-X.Y.(Z-1),其中 X.Y.Z 是当前发布版本)。

方法:复制 maint

git branch maint-X.Y.(Z-1) maint

maint 分支现在应该快进到新发布的代码,以便可以为当前版本跟踪维护修复

方法:将 maint 更新到新版本
  • git checkout maint

  • git merge --ff-only master

如果合并失败,因为它不是快进(fast-forward),那么可能是 maint 上的一些修复在功能发布中被遗漏了。如果按照前一节所述验证了分支的内容,这种情况就不会发生。

功能发布后 next 和 seen 的分支管理

在功能发布之后,集成分支 next 可以选择性地使用 next 上幸存的主题从 master 的尖端回退并重建

方法:回退并重建 next
  • git switch -C next master

  • git merge ai/topic_in_next1

  • git merge ai/topic_in_next2

  • ……

这样做的好处是 next 的历史记录将是干净的。例如,一些合并到 next 中的主题最初看起来很有希望,但后来被发现是不理想的或不成熟的。在这种情况下,主题会从 next 中恢复,但历史记录中仍保留它曾经被合并和恢复的事实。通过重建 next,你为这些主题的另一次化身提供了重新尝试的空白,而功能发布是历史中进行此操作的好时机。

如果这样做,你应该发布公告,说明 next 已被回退并重建。

相同的回退和重建过程也可以用于 seen。无需发布公告,因为 seen 如上所述是一个抛弃式分支。

分布式工作流

看完上一节,你应该知道如何管理主题了。通常,你不会是唯一在这个项目上工作的人,因此你必须分享你的工作。

粗略地说,有两种重要的工作流:合并和补丁。重要的区别在于,合并工作流可以传播完整的历史记录,包括合并,而补丁则不能。两种工作流可以并行使用:在 git.git 中,只有子系统维护者使用合并工作流,而其他人则发送补丁。

请注意,维护者可能会施加限制,例如所有提交/补丁必须遵循的“Signed-off-by”要求。请查阅你项目的文档以获取更多信息。

合并工作流

合并工作流通过在上游和下游之间复制分支来工作。上游可以将贡献合并到官方历史记录中;下游基于官方历史记录进行工作。

有三种主要工具可用于此

  • git-push[1] 将你的分支复制到远程仓库,通常是所有相关方都能读取的仓库;

  • git-fetch[1] 将远程分支复制到你的仓库;以及

  • git-pull[1] 一次性完成获取和合并。

请注意最后一点。除非你确实想合并远程分支,否则不要使用 git pull

获取变更很容易

方法:推送/拉取:发布分支/主题

git push <remote> <branch> 并告诉大家他们可以从哪里获取。

你仍然必须通过其他方式(例如邮件)告诉人们。(Git 提供了 git-request-pull[1] 向维护者发送预格式化的拉取请求,以简化此任务。)

如果你只是想获取集成分支的最新副本,保持最新状态也很容易

方法:推送/拉取:保持最新

使用 git fetch <remote>git remote update 来保持最新。

然后只需按照前面所述,从稳定的远程分支中派生你的主题分支即可。

如果你是维护者,并且想将其他人的主题分支合并到集成分支中,他们通常会通过邮件发送请求。这样的请求看起来像

Please pull from
    <URL> <branch>

在这种情况下,git pull 可以一次性完成获取和合并,如下所示。

方法:推送/拉取:合并远程主题

git pull <URL> <branch>

偶尔,维护者在尝试从下游拉取变更时可能会遇到合并冲突。在这种情况下,他们可以要求下游执行合并并自行解决冲突(也许他们更清楚如何解决这些冲突)。这是下游应该从上游合并的少数情况之一。

补丁工作流

如果你是一名以邮件形式发送上游变更的贡献者,你应该像往常一样使用主题分支(见上文)。然后使用 git-format-patch[1] 生成相应的邮件(强烈建议不要手动格式化,因为它让维护者的工作更容易)。

方法:format-patch/am:发布分支/主题
  • git format-patch -M upstream..topic 将它们转换为预格式化的补丁文件

  • git send-email --to=<recipient> <patches>

请参阅 git-format-patch[1]git-send-email[1] 手册页以获取进一步的使用说明。

如果维护者告诉你你的补丁不再适用于当前的上游,你将必须变基你的主题(你不能使用合并,因为你无法对合并结果进行 format-patch)

方法:format-patch/am:保持主题最新

git pull --rebase <URL> <branch>

你可以在变基过程中修复冲突。大概除了通过邮件之外,你还没有发布过你的主题,所以变基它不是问题。

如果你收到了这样一个补丁系列(作为维护者,或者作为其发送到的邮件列表的读者),请将邮件保存为文件,创建一个新的主题分支,并使用 git am 导入这些提交

方法:format-patch/am:导入补丁

git am < patch

一个值得指出功能是三路合并,如果你遇到冲突可以提供帮助:git am -3 将使用补丁中包含的索引信息来计算合并基。请参阅 git-am[1] 以获取其他选项。

GIT

Git[1] 套件的一部分