Git
英文 ▾ 主题 ▾ 最新版本 ▾ 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 以供下一个版本使用。

向上合并

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

规则:向上合并

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

这提供了非常受控的修复流程。如果您注意到您已将修复应用于例如需要在maint 中使用的master,则需要将其向下 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 钩子来执行与发布相关的项目,例如构建发布压缩包和预格式化的文档页面。

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

发布更改很容易

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

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/am:保持主题最新

git pull --rebase <URL> <branch>

然后您可以在重新设置期间修复冲突。据推测,您除了通过邮件发布主题之外,没有发布过其他内容,因此重新设置主题没有问题。

如果您收到此类补丁系列(作为维护者,或者可能是邮件列表的读者),请将邮件保存到文件中,创建一个新的主题分支并使用git am导入提交

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

git am < patch

值得指出的一项功能是三方合并,如果遇到冲突,它可以提供帮助:git am -3 将使用补丁中包含的索引信息来确定合并基础。有关其他选项,请参阅 git-am[1]

GIT

git[1] 套件的一部分

scroll-to-top