GitLab流

GitLab Flow简介

git的版本管理使得分支和合并比旧的版本管理系统(如SVN)容易得多。这允许多种分支策略和工作流。几乎所有这些都是对git之前使用的方法的改进。但是,许多组织最终得到的工作流没有明确定义,过于复杂,或者没有与问题跟踪系统集成。因此,我们建议将GitLab流程作为明确定义的最佳实践集。它结合了功能驱动开发特性分支问题跟踪。

从其他版本控制系统转向git的组织经常发现很难开发有效的工作流。本文描述了将git工作流与问题跟踪系统集成在一起的GitLab流程。它提供了一种简单、透明和有效的方式来使用git。

四个阶段(工作拷贝、索引、本地回购、远程回购),中间有三步

当转换到git时,你必须习惯这样一个事实,即在与同事共享提交之前有三个步骤。大多数版本控制系统只有一个步骤,即从工作副本提交到共享服务器。在git中,您可以将工作副本中的文件添加到暂存区域。之后,将它们提交到本地回购。第三步是推送到共享的远程存储库。在习惯了这三个步骤之后,分支模型就变成了挑战。

多个长时间运行的分支,并在各个方向上合并

由于许多刚接触git的组织没有使用它的惯例,它很快就会变得一团糟。他们遇到的最大问题是许多长时间运行的分支,每个分支都包含周围的部分更改。人们很难确定应该在哪个分支上开发或部署到生产环境中。对这个问题的反应通常是采用标准化的模式,例如git流GitHub流。我们认为仍有改进的空间,并将详细介绍一组我们称之为GitLab流程的实践。

Git流程及其问题

Vincent Driessen的Git Flow时间轴,经许可使用

Git flow是最早使用Git分支的提议之一,它得到了很多关注。它提倡一个主分支和一个独立的开发分支,以及支持特性、发布和修复的分支。开发在开发分支上进行,移动到发布分支,并最终合并到主分支中。Git流是一个定义良好的标准,但它的复杂性带来了两个问题。第一个问题是开发人员必须使用开发分支而不是主分支,主分支是为发布到生产环境的代码保留的。惯例是将默认分支称为master,并从这个分支进行大部分分支和合并。由于大多数工具会自动将主分支设置为默认分支并显示为默认分支,所以切换到另一个分支是很烦人的。git流的第二个问题是hotfix和release分支带来的复杂性。这些分支对某些组织来说是一个好主意,但对绝大多数组织来说是多余的。如今,大多数组织都在实践持续交付,这意味着可以部署您的默认分支。 This means that hotfix and release branches can be prevented including all the ceremony they introduce. An example of this ceremony is the merging back of release branches. Though specialized tools do exist to solve this, they require documentation and add complexity. Frequently developers make a mistake and for example changes are only merged into master and not into the develop branch. The root cause of these errors is that git flow is too complex for most of the use cases. And doing releases doesn't automatically mean also doing hotfixes.

GitHub流作为一个更简单的替代方案

合并了特征分支的主分支

作为对git flow的回应,详细介绍了一个更简单的替代方案,GitHub流。这个流只有特性分支和一个主分支。这是非常简单和干净的,许多组织都采用了它,并取得了巨大的成功。Atlassian建议类似的策略尽管它们重新建立了特征分支。将所有内容合并到主分支并进行部署通常意味着您将“库存”中的代码量最小化,这符合精益和持续交付的最佳实践。但是这个流程仍然留下了许多关于部署、环境、发布和集成问题的未解之谜。在GitLab流程中,我们为这些问题提供了额外的指导。

使用GitLab流程的生产分支

主分支和生产分支带有指示部署的箭头

每次合并一个特性分支时,GitHub流都假定您能够部署到生产环境中。这对于例如SaaS应用程序来说是可能的,但在许多情况下这是不可能的。一种情况是,你无法控制确切的发布时间,例如iOS应用需要通过App Store验证。另一个例子是当你有部署窗口(工作日从上午10点到下午4点,当运维团队满负荷时),但你也在其他时间合并代码。在这些情况下,您可以创建一个反映部署代码的生产分支。您可以通过将master合并到生产分支来部署新版本。如果您需要知道生产环境中有哪些代码,只需签出生产环境分支即可查看。在版本控制系统中,通过合并提交可以很容易地看到部署的大致时间。如果您自动部署生产分支,那么这个时间非常准确。如果需要更精确的时间,可以让部署脚本在每个部署上创建一个标记。 This flow prevents the overhead of releasing, tagging and merging that is common to git flow.

环境分支与GitLab流

多个分支,代码从一个级联到另一个

拥有一个自动更新到主分支的环境可能是个好主意。只有在这种情况下,此环境的名称才可能与分支名称不同。假设您有一个登台环境、一个预生产环境和一个生产环境。在这种情况下,主分支部署在暂存上。当有人想要部署到预生产时,他们会创建一个从主分支到预生产分支的合并请求。并且通过将预生产分支合并到生产分支中来实现代码的上线。这个只向下游提交的工作流确保了所有的东西都在所有的环境中进行了测试。如果你需要选择一个带有热修复的提交,通常是在一个特性分支上开发它,然后用合并请求将它合并到master中,不要删除这个特性分支。如果师父是好的(如果你在练习应该是好的)持续交付),然后将其合并到其他分支。如果这是不可能的,因为需要更多的手工测试,您可以将合并请求从特性分支发送到下游分支。

使用GitLab流发布分支

Master和多个发布分支,这些分支的长度随Master的精选而变化

只有当你需要向外界发布软件时,你才需要使用发布分支。在这种情况下,每个分支包含一个小版本(2-3-stable, 2-3- 4-stable,等等)。稳定分支使用master作为起点,并尽可能晚地创建。通过尽可能晚地进行分支,可以最大限度地减少将错误修复应用于多个分支的时间。在发布分支发布之后,只有严重的错误修复才会包含在发布分支中。如果可能的话,这些bug修复首先合并到master中,然后再被挑选到发布分支中。这样,您就不会忘记将它们挑选到主版本中,并在后续版本中遇到相同的错误。这就是所谓的“上游优先”策略谷歌红色的帽子。每次在发布分支中包含错误修复时,补丁版本都会被提出(以遵守)语义版本控制),通过设置一个新标签。有些项目还有一个稳定的分支,指向与最新发布的分支相同的提交。在这个流中,通常不会有生产分支(或git流主分支)。

合并/拉请求与GitLab流

合并带有行注释的请求

合并或拉取请求是在git管理应用程序中创建的,并要求指定的人员合并两个分支。GitHub和Bitbucket等工具选择了拉请求的名称,因为第一个手动操作将是拉功能分支。诸如GitLab和其他工具选择名称合并请求,因为这是对受让人请求的最终操作。在本文中,我们将它们称为合并请求。

如果你在一个特性分支上工作了几个小时以上,那么最好与团队的其他成员分享中间结果。这可以通过创建合并请求而不将其分配给任何人来完成,而不是在描述或评论中提到人员(/cc @mark @susan)。这意味着它还没有准备好被合并,但欢迎反馈。您的团队成员可以对合并请求进行一般注释,也可以对带有行注释的特定行进行注释。合并请求作为代码审查工具,不需要像Gerrit和reviewboard这样的单独工具。如果审查发现了缺点,任何人都可以提交并推动修复。通常这样做的人是合并/提取请求的创建者。当新的提交被推入分支时,合并/拉取请求中的差异会自动更新。

当您对合并感到满意时,您可以将其分配给最了解您正在更改的代码库的人,并提及您希望获得反馈的任何其他人。有更多反馈的空间,在被分配的人对结果感到满意之后,分支就被合并了。如果被分配的人员感到不舒服,他们可以在不合并的情况下关闭合并请求。

在GitLab中,通常会保护长寿命的分支(例如主分支),以便普通开发人员不能修改这些受保护的分支吗。因此,如果您想将其合并到受保护的分支中,您可以将其分配给具有主授权的人。

使用GitLab流跟踪问题

将请求与显示的分支名称15-require-a-password-to-change-it和指派人员字段合并

GitLab流是一种使代码和问题跟踪器之间的关系更加透明的方法。

对代码的任何重大更改都应该从描述目标的问题开始。每次代码更改都有一个原因,这对于通知团队中的每个人,并帮助人们保持特性分支的范围较小是很重要的。在GitLab中,对代码库的每次更改都始于问题跟踪系统中的一个问题。如果没有问题,则应首先创建问题,前提是涉及重大工作(超过1小时)。对于许多组织来说,这是很自然的,因为问题必须在sprint中进行评估。发行标题应该描述系统的理想状态,例如:“作为管理员,我想在不收到错误的情况下删除用户”而不是“管理员不能删除用户”。

当您准备好编写代码时,您可以从主分支为该问题启动一个分支。该分支的名称应该以发行号开头,例如“15- require_a -password-to-change-it”。

当您完成或想要讨论代码时,您打开合并请求。这是一个讨论更改和审查代码的在线场所。打开合并请求是一个手动操作,因为您并不总是想要合并您推送的新分支,它可能是一个长时间运行的环境或发布分支。如果您打开合并请求,但没有将其分配给任何人,则它是“正在进行的工作”合并请求。它们用于讨论提议的实现,但还没有准备好包含在主分支中。专家提示:以开始合并请求的标题(在制品)在制品:以防止它在准备好之前被合并。

当作者认为代码准备好了,合并请求就被分配给审阅者。当审阅者认为代码已经准备好包含在主分支中时,他们按下合并按钮。在这种情况下,代码被合并,并生成一个合并提交,使该事件在以后很容易看到。合并请求总是创建一个合并提交,即使没有合并提交也可以添加。这种合并策略在git中称为“无快进”。合并后的特性分支被删除,因为它不再需要,在GitLab中,这个删除是合并时的一个选项。

假设合并了一个分支,但是出现了一个问题,并且重新打开了该问题。在这种情况下,重用相同的分支名称没有问题,因为它是在合并分支时删除的。在任何时候,每个问题最多有一个分支。一个特性分支可能解决多个问题。

链接和关闭来自合并请求的问题

显示将被关闭的链接问题的合并请求

可以通过在提交消息(fixes #14, closing #67,等等)或合并请求描述中提到问题来链接问题。然后,GitLab创建指向上述问题的链接,并在链接到合并请求的相应问题中创建注释。

一旦代码合并到默认分支中,这些问题就会关闭。

如果你只是想做一个参考而不想结束这个问题,你也可以直接提到它:“Duck typing是首选。# 12”。

如果您的问题跨越多个存储库,最好的方法是为每个存储库创建一个问题,并将所有问题链接到父问题。

用rebase压缩提交

显示rebase视图的Vim屏幕

使用git,您可以使用交互式rebase (变基-我)将多个提交压缩成一个并重新排序。在GitLab EE和。com中你也可以合并前重base从web界面。如果您在开发过程中对小的更改进行了多次提交,并希望用单个提交替换它们,或者希望使顺序更合乎逻辑,则此功能非常有用。但是,您永远不应该将已推送到远程服务器的提交重新基化。有人可能已经提到了提交,或者挑选了它们。当您重新定位时,您更改了提交的标识符(SHA-1),这很容易引起混淆。如果您这样做,相同的更改将在多个标识符下被知道,这可能会导致很多混乱。如果人们已经审查了你的代码,那么他们很难只审查你在那之后所做的改进,如果你把所有的东西都重新提交到一次提交中。另一个不进行重基的原因是你丢失了作者信息,也许有人创建了一个合并请求,另一个人推送了一个提交来改进它,第三个人合并了它。在这种情况下,将所有提交合并到一起会阻止其他作者正确地归属和共享部分代码git责备

鼓励人们经常提交和频繁地推送到远程存储库,这样其他人就知道每个人都在做什么。这将导致每次更改都要进行多次提交,从而使历史记录更难以理解。但是拥有稳定标识符的好处大于这个缺点。为了理解上下文的变化,我们可以查看合并提交,当代码合并到主分支时,合并提交将所有提交组合在一起。

在将多个提交从一个特性分支合并到主分支后,这就很难撤销了。如果你把所有的提交压缩成一个提交,你就可以恢复这个提交,但是正如我们指出的,你不应该在提交被推送后重新定位。幸运的是恢复一段时间前的合并可以用git完成。但是,这需要对想要恢复的提交进行特定的合并提交。如果您对合并进行了恢复,但是您改变了主意,那么就进行恢复,而不是再次合并,因为git不允许您再次合并代码。

在手动合并时创建合并提交是一个很好的理由,因为能够恢复合并——no-ff选择。当你接受合并请求时,Git管理软件总是会创建一个合并提交。

不使用rebase命令提交吗

顺序合并提交列表

使用git,你还可以重新调整你的特性分支提交,让它们在主分支提交之后进行排序。这可以防止在将master合并到特性分支并创建一个很好的线性历史时创建合并提交。但是,就像压缩一样,您永远不应该对推送到远程服务器的提交进行重基。这使得您无法重新定位已经与您的团队共享的正在进行的工作,这是我们推荐的。当使用rebase来更新你的特性分支时需要一次又一次地解决类似的冲突。您有时可以重用记录的分辨率(verere),但是如果不重新定位,您只需要解决一次冲突就可以了。必须有更好的方法来避免多次合并提交。

防止创建许多合并提交的方法是不要频繁地将master合并到特性分支中。我们将讨论在master中合并的三个原因:利用代码、合并冲突和长时间运行的分支。如果您需要利用在创建特性分支后在master中引入的一些代码,您有时可以通过选择一个提交来解决这个问题。如果您的特性分支有合并冲突,创建合并提交是解决这个问题的正常方法。可以使用来防止一些合并冲突gitattributes对于可以以随机顺序排列的文件。例如,在GitLab中,我们的变更日志文件在.gitattributes中指定为更新日志。md合并=联盟这样就会有更少的合并冲突。创建合并提交的最后一个原因是拥有长期存在的分支,您希望与项目的最新状态保持同步。马丁·福勒他关于特性分支的文章谈到了这种持续集成(CI)。在GitLab,我们很容易混淆CI和分支测试。引用Martin Fowler的话:“我听过有人说他们在做CI,因为他们正在运行构建,也许使用CI服务器,在每个分支上进行每次提交。这是持续构建,也是一件好事,但没有整合,所以这不是持续集成。”防止多次合并提交的解决方案是保持特性分支的寿命较短,绝大多数分支的工作时间应该少于一天。如果您的特性分支通常需要超过一天的工作时间,请寻找方法来创建更小的工作和/或使用单元功能切换。对于耗时超过一天的长时间分支机构,有两种策略。在CI策略中,您可以在一天开始时合并master,以防止稍后的合并带来的痛苦。在同步点策略中,您只能从定义良好的时间点进行合并,例如标记的发布。这个策略是由莱纳斯·托瓦兹倡导因为代码在这些点上的状态是众所周知的。

总之,我们可以说,您应该尝试阻止合并提交,而不是消除它们。你的代码库应该是干净的,但是你的历史记录应该代表实际发生的事情。开发软件是在小而混乱的步骤中发生的,让您的历史反映这一点是可以的。您可以使用工具查看提交的网络图,并了解创建代码的混乱历史。如果您修改了代码,历史记录是不正确的,并且工具无法补救这个问题,因为它们无法处理更改提交标识符。

奖励问题和合并请求的表情符号

在GitLab的表情吧

通常使用+1或-1表示赞成或不赞成。在GitLab中,你可以使用表情符号在问题和合并请求上击掌。

推拔树枝

删除合并请求中分支的复选框

我们建议人们经常推动他们的特性分支,即使他们还没有准备好进行审查。通过这样做,您可以防止团队成员意外地开始处理同一个问题。当然,这种情况应该已经通过在问题跟踪软件中分配人员来防止了。然而,有时双方中的一方忘记在问题跟踪软件中分配人员。在一个分支被合并之后,它应该从源代码控制软件中移除。在GitLab和类似的系统中,这是合并时的一个选项。这确保了存储库管理软件中的分支概览只显示正在进行的工作。这也确保了当有人重新打开issue时,可以毫无问题地使用具有相同名称的新分支。重新打开问题时,需要创建新的合并请求。

经常承诺,并传达正确的信息

好的和坏的提交消息

我们建议尽早、经常地做出承诺。每次有了一组有效的测试和代码,就可以进行提交。这样做的好处是,当扩展或重构出错时,很容易恢复到工作版本。对于以前使用SVN的程序员来说,这是一个很大的变化,他们过去常常在工作准备好共享时提交。诀窍是,当你的工作准备好共享时,使用合并/拉取请求和多次提交。提交消息应该反映您的意图,而不是提交的内容。无论如何,提交的内容都很容易看到,问题是为什么要这样做。一个好的提交消息的例子是:“组合模板来清空用户视图。”有些词是糟糕的提交消息,因为它们没有包含太多的信息:change, improve和refactor。单词fix或fixes也是一个危险信号,除非它出现在提交语句之后并引用问题号。 To see more information about the formatting of commit messages please see this great蒂姆·波普的博客文章

合并前测试

合并请求显示测试状态,红色,黄色和绿色

在旧的工作流中,持续集成(CI)服务器通常只在主分支上运行测试。开发人员必须确保他们的代码不会破坏主分支。当使用GitLab流开发人员从这个主分支创建分支时,它必须是绿色的。因此,每个合并请求必须在接受之前进行测试。像Travis和GitLab这样的CI软件会在合并请求中直接显示构建结果,从而使合并变得简单。一个缺点是他们测试的是特性分支本身,而不是合并后的结果。要改进这一点,可以测试合并后的结果本身。问题是每次合并到master时,合并结果都会发生变化。每次提交到主服务器时重新测试在计算上是昂贵的,并且意味着您需要更频繁地等待测试结果。如果没有合并冲突,并且特性分支是短期的,那么风险是可以接受的。 If there are merge conflicts you merge the master branch into the feature branch and the CI server will rerun the tests. If you have long lived feature branches that last for more than a few days you should make your issues smaller.

使用特性分支

Shell输出显示git拉出输出

当启动一个特性分支时,总是从一个最新的宿主开始分支。如果你事先知道你的工作完全依赖于另一个分支,你也可以从那里进行分支。如果在开始后需要合并到另一个分支,请在合并提交中解释原因。如果你还没有将提交推送到共享位置,你也可以在master或其他特性分支上进行重基。不要在上游进行合并,如果你的代码可以正常工作,并且无需这样做就可以干净地合并,Linus甚至说你永远不应该在上游的随机点进行合并,只应该在主版本中进行合并。只在需要的时候合并,可以防止在特性分支中创建合并提交,而这些提交后来会导致主历史记录混乱。

参考文献

Baidu
map