中文 ▾ 主题 ▾ 最新版本 ▾ 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]

合并有很多优点,因此我们尝试仅通过合并来解决尽可能多的问题。 Cherry-picking 偶尔仍然有用; 有关示例,请参见下面的“向上合并”。

最重要的是,合并在分支级别工作,而 cherry-picking 在提交级别工作。 这意味着合并可以轻松地携带 1、10 或 1000 个提交中的更改,这意味着工作流程可以更好地扩展到大量贡献者(和贡献)。 合并也更容易理解,因为合并提交是一个“承诺”,即现在包含其所有父项中的所有更改。

当然,这是一种权衡:合并需要更仔细的分支管理。 以下小节讨论了要点。

晋升

随着给定的功能从实验性到稳定,它也会在软件的相应分支之间“晋升”。 git.git 使用以下集成分支

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

  • master 跟踪应进入下一个版本的提交;

  • next 旨在作为 master 稳定性的测试分支。

还有一个略有不同的第四个官方分支

  • seen(维护者看到的补丁)是一个集成分支,用于尚未完全准备好包含的内容(请参见下面的“集成分支”)。

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

从概念上讲,该功能进入一个不稳定的分支(通常是 nextseen),并在被认为足够稳定后“晋升”到下一个版本的 master

向上合并

但是,不能通过实际向下合并来完成上面讨论的“向下晋升”,因为这会将不稳定分支上的所有更改合并到稳定分支中。 因此,以下

规则:向上合并

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

这提供了非常可控的修复流程。 如果您注意到您已将修复应用于 master 等,并且 maint 也需要该修复,则需要向下 cherry-pick 它(使用 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

步骤:验证 mastermaint 的超集

git log master..maint

这个命令不应该列出任何提交。否则,检出 master 并将 maint 合并到它。

现在你可以继续创建功能发布版本。在 master 的顶端应用一个标签,表明发布版本

步骤:发布版本标签

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

你需要将新的标签推送到一个公共 Git 服务器(见下面的“分布式工作流”)。这使得这个标签可以被其他跟踪你项目的人使用。推送也可能触发一个 post-update hook 来执行与发布相关的项目,例如构建发布 tarballs 和预格式化的文档页面。

类似地,对于维护版本,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

如果合并失败,因为它不是快进,那么可能是 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

将更改推送出去很容易

步骤:Push/pull:发布分支/主题

git push <remote> <branch> 并告诉所有人他们可以从哪里抓取。

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

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

步骤:Push/pull:保持最新

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

然后,只需像之前解释的那样,从稳定的 remotes 分支你的主题分支。

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

Please pull from
    <URL> <branch>

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

步骤:Push/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] 手册页。

如果维护者告诉你你的补丁不再适用于当前的上游,你将不得不 rebase 你的主题(你不能使用合并,因为你不能 format-patch 合并)

步骤:format-patch/am:保持主题最新

git pull --rebase <URL> <branch>

然后你可以在 rebase 期间修复冲突。据推测,除了通过邮件之外,你没有发布你的主题,因此 rebasing 它不是问题。

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

步骤:format-patch/am:导入补丁

git am < patch

一个值得指出的功能是三向合并,它可以帮助你解决冲突:git am -3 将使用补丁中包含的索引信息来确定合并基础。有关其他选项,请参见 git-am[1]

GIT

git[1] 套件的一部分

scroll-to-top