385

我们公司目前正在使用一个简单的主干/发布/修补程序分支模型,并希望就哪些分支模型最适合您的公司或开发过程提供建议。

  1. 工作流/分支模型

    以下是我所看到的对此的三个主要描述,但它们之间存在部分矛盾,或者不足以理清我们遇到的后续问题(如下所述)。因此,到目前为止,我们的团队默认的解决方案不是那么好。你在做更好的事情吗?

  2. 合并与变基(纠结与顺序历史)

    是否应该pull --rebase等待合并回主线,直到您的任务完成?就我个人而言,我倾向于合并,因为它保留了任务开始和完成的视觉说明,我什至更喜欢merge --no-ff这个目的。然而,它还有其他缺点。许多人还没有意识到合并的有用属性——它不是可交换的(将主题分支合并到主分支并不意味着将主分支合并到主题分支)。

  3. 我正在寻找一个自然的工作流程

    有时会发生错误,因为我们的程序没有使用简单的规则捕捉特定情况。例如,早期版本所需的修复当然应该基于足够的下游,以便可以将上游合并到所有必要的分支中(这些术语的使用是否足够清楚?)。然而,在开发人员意识到它应该被放置在更下游的地方之前,一个修复程序会使其成为主控器,如果它已经被推送(更糟糕的是,合并或基于它的东西),那么剩下的选项就是樱桃采摘,与其相关的危险。你使用什么样的简单规则?这还包括一个主题分支的尴尬,它必然排除其他主题分支(假设它们是从一个公共基线分支的)。开发人员不想完成一个功能来启动另一个功能,感觉就像他们刚刚编写的代码已经不存在了

  4. 如何避免创建合并冲突(由于樱桃挑选)?

    似乎创建合并冲突的可靠方法是在分支之间进行挑选,它们永远不能再次合并?在任一分支中应用相同的提交恢复(如何做到这一点?)可能会解决这种情况?这是我不敢推动很大程度上基于合并的工作流程的原因之一。

  5. 如何分解成局部分支?

    我们意识到从主题分支组装一个完整的集成会很棒,但是我们的开发人员的工作通常没有明确定义(有时就像“四处寻找”一样简单),如果某些代码已经进入“杂项”主题,根据上面的问题,它不能再次被带出那里吗?您如何定义/批准/毕业/发布您的主题分支?

  6. 像代码审查和毕业这样的适当程序当然会很可爱。

    但是我们根本无法让事情变得足够解开来管理这个 - 有什么建议吗?集成分支,插图?

以下是相关问题的列表:

还可以查看 Plastic SCM 写的关于任务驱动开发的内容,如果 Plastic 不是您的选择,请研究nvie 的分支模型和他的支持脚本

4

4 回答 4

93

DVCS 新开发人员需要实现的最令人不安的功能是发布过程

  • 您可以导入(获取/拉取)您需要的任何远程仓库
  • 您可以发布(推送)到您想要的任何(裸)回购

从那以后,您可以遵守一些规则以使您的问题更容易:

  • 仅在尚未推送时才重新设置分支(自上次重新设置后未推送)
  • 只推送到一个裸仓库(从 Git1.7 开始是强制性的)
  • 遵循Linus 关于变基和合并的建议

现在:

工作流程/分支模型

每个工作流程都支持发布管理流程,并且是为每个项目量身定制的。
我可以添加到您提到的工作流程中的是:每个开发人员不应该创建一个功能分支,而应该只创建一个“当前开发”分支,因为事实是:开发人员通常不知道他/她的分支会产生什么:一个功能,几个(因为它最终成为一个过于复杂的功能),没有(因为没有及时准备好发布),另一个功能(因为原来的功能已经“变形”),...

只有“集成商”才能在“中央”存储库上建立官方功能分支,然后开发人员可以获取这些分支以重新定位/合并适合该功能的工作部分。

合并与变基(纠结与顺序历史)

我喜欢你提到的我的回答(“内部开发的 git 使用的工作流程描述”)

我正在寻找一个自然的工作流程

对于修复,它可以帮助将每个修复与来自错误跟踪的票据相关联,这有助于开发人员记住他/她应该在哪里(即在哪个分支上,即“用于修复”的专用分支)提交此类修改。
然后钩子可以帮助保护中央存储库免受未经验证的错误修复或不应该从中推送的分支的推送。(这里没有具体的解决方案,这一切都需要适应你的环境)

如何避免创建合并冲突(由于樱桃挑选)?

正如Jakub Narębski他的回答中所说,樱桃采摘应该保留在需要的罕见情况下。
如果您的设置涉及大量挑选樱桃(即“它并不罕见”),那么有些事情是错误的。

将在还原中应用相同的提交(如何做到这一点?)

git revert应该注意这一点,但这并不理想。

如何分解成局部分支?

只要一个分支还没有被推送到任何地方,开发人员就应该将其提交历史(一旦他/她最终看到开发采取更明确和稳定的形式)重新组织为:

  • 如果需要,有几个分支(一个明确识别的特征)
  • 一个分支中的一组连贯的提交(请参阅Trimming Git Checkins

适当的程序,例如代码审查和毕业?

集成分支(在专用集成中)存储库可以帮助开发人员:

  • 将他/她的开发重新建立在远程集成分支之上(pull --rebase)
  • 就地解决
  • 将开发推向该回购
  • 与不会导致混乱的集成商核对;)
于 2010-04-12T12:01:40.937 回答
22

我认为,我可能错了,关于 git 最被误解的一件事是它的分布式特性。这使得以您可以工作的方式说颠覆非常不同,尽管您可以根据需要模仿 SVN 行为。问题几乎是任何工作流程都会做的,这很好,但也有误导性。

如果我对内核开发的理解(我会专注于这一点)是对的,那么每个人都有自己的 git 存储库来开发内核。Torvalds 负责管理一个存储库 linux-2.6.git,它充当发布存储库。如果人们希望开始针对“发布”分支开发功能,则可以从这里克隆。

其他存储库进行了一些开发。这个想法是从 linux-2.6 克隆,分支出任意多次,直到你有了一个工作的“新”特性。然后,当它准备好后,您可以将其提供给被认为值得信赖的人,他们会将这个分支从您的存储库拉到他们的存储库中,并将其合并到主流中。在 linux 内核中,这发生在几个级别(受信任的副手)上,直到它到达 linux-2.6.git,此时它成为“内核”。

现在这是令人困惑的地方。分支名称根本不需要跨存储库保持一致。所以我可以在我的存储库git pull origin master:vanilla-codeorigin的一个名为vanilla-code. 如果我知道发生了什么,那真的没关系 - 它是分布式的,因为所有存储库都是彼此对等的,而不仅仅是像 SVN 这样的多台计算机共享。

因此,考虑到所有这些:

  1. 我认为这取决于每个程序员如何进行分支。您所需要的只是一个用于管理发布等的中央存储库。主干可以是head. 发布可能是标签或分支,而修补程序本身可能是分支。事实上,我可能会以分支的形式发布,这样你就可以继续修补它们。
  2. 我会合并而不是变基。例如,如果您获取一个存储库,克隆它,分支并进行一些开发,然后从您的存储库中提取origin您应该在您的存储库中创建另一个分支并将最新的合并masteryourbranch,以便其他人可以轻松地提取您的更改可能的。根据我的经验,很少需要真正变基。
  3. 我认为这是一个了解 Git 工作方式及其功能的案例。这确实需要一段时间和很多良好的沟通——当我开始与其他开发人员一起使用 git 时,我才真正开始了解发生了什么,即使是现在,有些事情我也不确定。
  4. 合并冲突很有用。我知道,我知道,您希望这一切都能正常工作,但是,事实是代码更改,您确实需要将结果合并到可以工作的东西中。合并冲突实际上只是更多的编程。我从来没有找到一个简单的解释来解释如何处理它们,所以这里是:注意有合并冲突的文件,去把它们改成它们应该的样子,git add .然后git commit.
  5. 不过很合适。正如我所说,每个用户的 git 存储库都是他们自己的,分支名称不需要相同。例如,如果您有一个暂存存储库,您可以强制执行命名模式,但您不需要为每个开发人员执行此操作,只需在发布存储库中执行即可。
  6. 这是合并阶段。当您考虑要审查/通过质量测试时,您只会合并到发布分支等。

我希望这会有所帮助。我意识到 VonC 刚刚发布了一个非常相似的解释......我打字速度不够快!

编辑一些关于如何在商业环境中使用 git 的进一步想法,因为这似乎与评论中的 OP 相关:

  • 发布存储库(我们将其称为product.git)可供许多负责实际管理产品本身的高级程序员/技术人员访问。它们类似于 OSS 中维护者的角色。
  • 这些程序员可能还部分领导新版本的开发,因此他们也可能自己编写代码并维护各种存储库。他们可能会为真正的新功能管理暂存存储库,并且他们也可能拥有自己的存储库。
  • 下面是负责开发各个位的程序员。例如,有人可能负责 UI 工作。因此,他们管理 UI.git 存储库。
  • 下面是实际的程序员,他们将这些功能开发为他们的日常工作。

那么会发生什么?好吧,每个人都在每天开始时从“上游”源,即发布存储库(也可能包含前几天开发的最新材料)中提取。每个人都直接这样做。这将在他们的存储库中的一个分支上进行,可能称为“master”,或者如果您是我,则可能称为“latest”。然后程序员会做一些工作。这项工作可能是他们不确定的事情,所以他们建立了一个分支,做这项工作。如果它不起作用,他们可以删除分支并返回。如果是这样,他们将不得不合并到他们当前正在处理的主分支中。我们会说这是一个 UI 程序员,latest-ui所以他确实git checkout latest-ui跟着git merge abc-ui-mywhizzynewfeature. 然后他告诉他的技术负责人(UI负责人)嘿,我已经完成了这样的任务,从我这里拉出来。所以 UI 负责人会这样做git pull user-repo lastest-ui:lastest-ui-suchafeature-abc。然后 UI 负责人在那个分支上查看它并说,实际上,这非常好,我会将它合并到ui-latest. ui-latest然后他可能会告诉他下面的每个人在他们的树枝上或者他们给他们起的任何名字上从他那里拉出来,这样开发人员就会探索这个功能。如果团队满意,UI 负责人可能会要求测试负责人从他那里提取并合并更改。这会传播给对其进行测试并提交错误报告等的每个人(更改的下游)。最后,如果该功能通过测试等,顶级技术主管之一可能会将其合并到程序的当前工作副本中,此时然后所有更改都会向下传播。等等。

这不是一种“传统”的工作方式,它被设计为“对等驱动”,而不是像 SVN/CVS 那样的“分层”。本质上,每个人都有提交权限,但仅限于本地。它是对存储库的访问以及您将哪个存储库指定为允许您使用层次结构的发布存储库。

于 2010-04-12T12:07:31.327 回答
10

我使用的一个效果很好的模型如下:

每个人都可以推入/拉出的“祝福”回购,基本上是一个客户端-服务器拓扑。

没有主分支,因此没有开发人员可以将任何代码推送到“主线”。

所有的发展都发生在主题分支上。我们命名了名称以轻松检测谁对此负责:jn/newFeature 或 jn/issue-1234

白板上的分支和看板/scrum 卡之间也存在近乎一对一的映射。

为了发布一个分支,它被推送到受祝福的 repo 并且看板卡被移动到准备好进行审查。

然后,如果该分支被审查接受,它就是一个发布的候选者。

当一组接受的分支合并在一起并用版本号标记时,就会发生发布。

通过将新标签推送到受祝福的存储库,新功能就有了新的可能基础。

为避免合并冲突,请开发人员将其未发布的分支更新(合并)到最新的发布标签。

于 2011-10-11T11:28:30.580 回答
2

就个人而言,我尝试只在 master 分支中保留可发布的代码。

当我处理新功能或错误修复时,我会在分支中进行。我也在分支中进行单元测试。如果一切正常,只有这样我才会合并/变基回到主控。

我也尝试使用常见的分支命名约定,例如:

  • 错误修复/recursive_loop
  • 错误修复/sql_timeout
  • 功能/新布局
  • 功能/增强搜索
于 2012-12-20T22:16:13.677 回答