设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.35.1 → 2.50.1 无更改
-
2.35.0
2022-01-24
- 2.28.1 → 2.34.8 无更改
-
2.28.0
2020-07-27
- 2.23.1 → 2.27.1 无更改
-
2.23.0
2019-08-16
- 2.18.1 → 2.22.5 无更改
-
2.18.0
2018-06-21
- 2.17.0 → 2.17.6 无更改
-
2.16.6
2019-12-06
- 2.13.7 → 2.15.4 无更改
-
2.12.5
2017-09-22
- 2.1.4 → 2.11.4 无更改
-
2.0.5
2014-12-17
描述
本文档试图阐述并说明 git.git
本身使用的一些工作流元素。许多理念具有普遍适用性,尽管对于涉及人数较少的较小项目,通常不需要完整的工作流。
我们制定了一套*规则*以供快速参考,同时散文部分试图说明每条规则的动机。请勿总是拘泥于字面意思;您应该更重视行动的充分理由,而非像本文档这样的手册页。
分离更改
作为一般规则,您应该尝试将更改拆分为小的逻辑步骤,并提交每个步骤。它们应该保持一致,独立于任何后续提交而工作,通过测试套件等。这使得审查过程更容易,并且历史记录对于后续的检查和分析更有用,例如使用 git-blame[1] 和 git-bisect[1]。
为了实现这一点,请从一开始就尝试将工作拆分为小步骤。将几个提交合并(squash)在一起总是比将一个大提交拆分成多个更容易。在过程中不要害怕步骤过小或不完美。您随时可以稍后回去,在发布提交之前使用 git
rebase
--interactive
编辑它们。您可以使用 git
stash
push
--keep-index
来独立于其他未提交的更改运行测试套件;请参阅 git-stash[1] 的 EXAMPLES 部分。
管理分支
有两种主要工具可用于将一个分支的更改包含到另一个分支上:git-merge[1] 和 git-cherry-pick[1]。
合并具有许多优点,因此我们尝试仅通过合并来解决尽可能多的问题。拣选(cherry-picking)偶尔仍然有用;请参阅下面的“向上合并”以获取示例。
最重要的是,合并是在分支级别操作,而拣选(cherry-picking)是在提交级别操作。这意味着合并可以轻松地引入来自 1、10 或 1000 个提交的更改,这反过来意味着工作流可以更好地扩展到大量贡献者(和贡献)。合并也更容易理解,因为合并提交是一个“承诺”,即其所有父提交的所有更改都已包含在内。
当然,这也有一个权衡:合并需要更仔细的分支管理。以下小节讨论了要点。
毕业
当一个给定功能从实验性走向稳定时,它也在软件的相应分支之间“毕业”。git.git
使用以下*集成分支*
-
*maint* 跟踪应该进入下一个“维护版本”的提交,即上次发布的稳定版本的更新;
-
*master* 跟踪应该进入下一个发行版的提交;
-
*next* 旨在作为测试分支,用于测试主题在 master 中的稳定性。
还有第四个官方分支,其用法略有不同
-
*seen*(维护者已查看的补丁)是一个集成分支,用于尚未完全准备好包含在内的内容(请参阅下面的“集成分支”)。
这四个分支通常都是其上方分支的直接后代。
从概念上讲,功能从不稳定分支(通常是 *next* 或 *seen*)进入,一旦被认为足够稳定,便“毕业”到 *master* 以供下一个发行版使用。
向上合并
然而,上面讨论的“向下毕业”不能通过实际向下合并来完成,因为那会将不稳定分支上的*所有*更改合并到稳定分支中。因此有以下规则:
始终将您的修复提交到需要它们的最旧受支持分支。然后(定期地)将集成分支向上合并到彼此中。
这提供了非常受控的修复流。如果您发现您已将修复应用于例如 *master* 分支,而 *maint* 分支也需要此修复,则需要向下拣选(使用 git-cherry-pick[1])。这种情况会发生几次,除非您非常频繁地这样做,否则无需担心。
主题分支
任何非平凡的功能都需要多个补丁来实现,并且在其生命周期内可能会获得额外的错误修复或改进。
直接在集成分支上提交所有内容会导致许多问题:不良提交无法撤销,因此必须逐一恢复,这会创建混乱的历史记录,并且当您忘记恢复一部分更改组时,还会产生进一步的错误潜力。并行工作会混淆更改,造成进一步的混乱。
使用“主题分支”解决了这些问题。这个名称非常不言自明,但有一个注意事项,它来自上面的“向上合并”规则
为每个主题(功能、错误修复等)创建一个侧分支。从您最终想要合并到的最旧的集成分支中分叉出来。
许多事情都可以很自然地完成
-
要将功能/错误修复合并到集成分支中,只需合并即可。如果主题在此期间进一步发展,请再次合并。(请注意,您不一定非要先将其合并到最旧的集成分支。例如,您可以先将错误修复合并到 *next*,给它一些测试时间,然后在您确定它稳定时合并到 *maint*。)
-
如果您发现需要从 *other* 分支获取新功能以继续处理您的主题,请将 *other* 合并到 *topic* 中。(但是,请勿“习惯性地”这样做,见下文。)
-
如果您发现自己从错误的分支分叉,并想将其“时光倒流”,请使用 git-rebase[1]。
请注意,最后一点与前两点冲突:已合并到其他地方的主题不应被变基。请参阅 git-rebase[1] 中关于 RECOVERING FROM UPSTREAM REBASE 的部分。
我们应该指出,“习惯性地”(没有任何真正理由地定期)将集成分支合并到您的主题中——以及由此引申开来,定期地将任何上游内容合并到任何下游内容中——是不被赞成的
除非有充分的理由,否则不要合并到下游:上游 API 更改影响您的分支;您的分支不再干净地合并到上游;等等。
否则,被合并的主题将突然包含不止一个(良好分离的)更改。由此产生的许多小型合并将极大地混淆历史记录。任何日后调查文件历史的人都必须查明该合并是否影响了开发中的主题。上游甚至可能无意中合并到“更稳定”的分支中。诸如此类。
一次性集成
如果您遵循了上一段,您现在将有许多小型主题分支,并且偶尔会想知道它们如何交互。也许合并它们的结果甚至无法工作?但另一方面,我们希望避免将它们合并到任何“稳定”的地方,因为此类合并不易撤销。
当然,解决方案是进行一次可以撤销的合并:合并到一个一次性分支中。
为了测试几个主题的交互,将它们合并到一个一次性分支中。您绝不能在此类分支上进行任何工作!
如果您(非常)清楚地表明此分支将在测试后立即删除,您甚至可以发布此分支,例如,让测试人员有机会使用它,或让其他开发人员有机会查看他们正在进行的工作是否兼容。git.git
就有一个这样的官方一次性集成分支,名为 *seen*。
发布版的分支管理
假设您正在使用上面讨论的合并方法,那么在发布项目时,您需要进行一些额外的分支管理工作。
特性发布版是从 *master* 分支创建的,因为 *master* 跟踪应进入下一个特性发布版的提交。
*master* 分支应该是 *maint* 的超集。如果此条件不成立,则 *maint* 包含一些未包含在 *master* 中的提交。因此,这些提交所代表的修复将不会包含在您的特性发布版中。
要验证 *master* 确实是 *maint* 的超集,请使用 git log
git
log
master..maint
此命令不应列出任何提交。否则,请检出 *master* 并将 *maint* 合并到其中。
现在您可以继续创建特性发布版。在 *master* 的顶端应用一个标签来指示发布版本
git
tag
-s
-m
"Git
X.Y.Z"
vX.Y.Z
master
您需要将新标签推送到公共 Git 服务器(请参阅下面的“分布式工作流”)。这使得标签可供跟踪您项目的其他人使用。推送还可以触发 post-update 钩子,以执行发布相关项目,例如构建发布 tar 包和预格式化的文档页面。
同样,对于维护发布版,*maint* 跟踪要发布的提交。因此,在上述步骤中,只需标记并推送 *maint* 而非 *master*。
特性发布版后的维护分支管理
在特性发布版之后,您需要管理您的维护分支。
首先,如果您希望继续为最近发布版之前的特性发布版发布维护修复,那么您必须创建另一个分支来跟踪该先前发布版的提交。
为此,当前维护分支将被复制到另一个以先前发布版本号命名的分支(例如 maint-X.Y.(Z-1),其中 X.Y.Z 是当前发布版)。
git
branch
maint-X.Y.
(Z-1
) maint
*maint* 分支现在应该快进到新发布的代码,以便为当前发布版跟踪维护修复。
-
git
checkout
maint
-
git
merge
--ff-only
master
如果合并失败,因为它不是快进,那么可能是特性发布版中遗漏了 *maint* 上的一些修复。如果按照上一节所述验证了分支内容,这种情况就不会发生。
特性发布版后 next 和 seen 的分支管理
在特性发布版之后,集成分支 *next* 可以选择性地回溯并从 *master* 的顶端重建,使用 *next* 上现存的主题。
-
git
switch
-C
next
master
-
git
merge
ai/topic_in_next1
-
git
merge
ai/topic_in_next2
-
……
这样做的好处是 *next* 的历史记录将是干净的。例如,一些合并到 *next* 中的主题最初可能看起来很有前景,但后来被发现是不受欢迎的或不成熟的。在这种情况下,该主题会从 *next* 中恢复(revert),但历史记录中仍保留着它曾经被合并和恢复的事实。通过重新创建 *next*,您为这些主题的另一次尝试提供了干净的起点,而特性发布版是执行此操作的一个良好历史点。
如果您这样做,那么您应该发布一份公开声明,表明 *next* 已被回溯并重建。
*seen* 也可以遵循相同的回溯和重建过程。由于 *seen* 是一个一次性分支,如上所述,因此不需要公开声明。
分布式工作流
看完上一节后,您应该知道如何管理主题。一般来说,您不会是项目上唯一工作的人,因此您必须分享您的工作。
粗略地说,有两种重要的工作流:合并工作流和补丁工作流。重要的区别在于合并工作流可以传播完整的历史记录,包括合并,而补丁工作流不能。这两种工作流可以并行使用:在 git.git
中,只有子系统维护者使用合并工作流,而其他所有人发送补丁。
请注意,维护者可能会施加限制,例如“Signed-off-by”要求,所有提交/补丁必须符合这些要求才能被包含。有关更多信息,请查阅您项目的文档。
合并工作流
合并工作流通过在上游和下游之间复制分支来工作。上游可以将贡献合并到官方历史记录中;下游则基于官方历史记录进行工作。
有三种主要工具可用于此目的
-
git-push[1] 将您的分支复制到远程仓库,通常是所有相关方都可以读取的仓库;
-
git-fetch[1] 将远程分支复制到您的仓库;以及
-
git-pull[1],它一次性完成抓取和合并。
注意最后一点。除非您确实想合并远程分支,否则*不要*使用 *git pull*。
发布更改很容易
git
push
<远程> <分支> 并告诉所有人从何处抓取。
您仍然需要通过其他方式(例如邮件)告诉人们。(Git 提供了 git-request-pull[1] 来向上游维护者发送预格式化的拉取请求,以简化此任务。)
如果您只想获取集成分支的最新副本,保持最新状态也很容易
使用 git
fetch
<远程> 或 git
remote
update
来保持最新。
然后只需按照前面所述,从稳定的远程分支分叉您的主题分支即可。
如果您是维护者,并希望将其他人的主题分支合并到集成分支中,他们通常会通过邮件发送请求。这样的请求看起来像
Please pull from <URL> <branch>
在这种情况下,*git pull* 可以一次性完成抓取和合并,如下所示。
git
pull
<URL> <分支>
偶尔,维护者在尝试从下游拉取更改时可能会遇到合并冲突。在这种情况下,他们可以要求下游执行合并并自行解决冲突(也许他们会更清楚如何解决)。这是下游*应该*从上游合并的少数情况之一。
补丁工作流
如果您是一位以电子邮件形式向上游发送更改的贡献者,您应该像往常一样使用主题分支(见上文)。然后使用 git-format-patch[1] 生成相应的电子邮件(强烈推荐,因为它比手动格式化更易于维护者操作)。
-
git
format-patch
-M
upstream..topic
将它们转换为预格式化的补丁文件 -
git
send-email
--to=
<收件人> <补丁>
有关更多使用说明,请参阅 git-format-patch[1] 和 git-send-email[1] 的手册页。
如果维护者告诉您您的补丁不再适用于当前上游,您将不得不变基您的主题(您不能使用合并,因为您无法对合并进行 format-patch 操作)
git
pull
--rebase
<URL> <分支>
然后您可以在变基期间解决冲突。据推测,您除了通过邮件之外没有发布过您的主题,因此对其进行变基不是问题。
如果您收到此类补丁系列(作为维护者,或者作为邮件列表的读者),请将邮件保存到文件,创建一个新的主题分支,然后使用 *git am* 导入提交。
git am < patch
值得指出的一项功能是三方合并,它可以在您遇到冲突时提供帮助:git
am
-3
将使用补丁中包含的索引信息来确定合并基础。有关其他选项,请参阅 git-am[1]。