哪些Git分支模型适合你?

我们公司目前使用的是简单的主干/发布/热修复分支模型,我们想知道哪种分支模型最适合您的公司或开发过程。

  1. < p > 工作流/分支模型

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

    • gitworkflows(7) Manual Page
    • (nvie)一个成功的Git分支模型
    • (reinh)一个敏捷团队的Git工作流
    • 李< / ul > < / >
    • < p > 合并vs重基(纠缠vs顺序历史)

      一个pull --rebase或等待合并回主线直到你的任务完成?就我个人而言,我倾向于合并,因为这保留了一个任务在哪个基础上开始和完成的可视化说明,为此我甚至更喜欢merge --no-ff。然而,它也有其他缺点。许多人还没有意识到合并的有用属性——它不是可交换的(将一个主题分支合并到master并不意味着将master合并到主题分支)

    • < p > 我正在寻找一个自然的工作流程

      有时,错误的发生是因为我们的程序没有用简单的规则捕获特定的情况。例如,早期版本所需的修复当然应该充分地基于下游,以便能够将上游合并到所有必要的分支中(这些术语的使用是否足够清楚?)然而,在开发人员意识到它应该被放置在更下游之前,修复程序就已经进入了master,如果它已经被推了(更糟糕的是,合并或基于它的其他东西),那么剩下的选择是选择性的,并伴有相关的风险。你用的是什么简单的规则?这还包括一个主题分支必然排除其他主题分支的尴尬情况(假设它们是从一个公共基线分支而来)。开发人员不希望在完成一个功能后再开始另一个功能,就像他们刚刚写的代码已经不存在了一样 < / p >

    • < p > 如何避免创建合并冲突(由于选择)?

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

    • < p > 如何分解成局部分支?

      我们意识到,从主题分支中组装一个完整的集成将是非常棒的,但我们的开发人员的工作通常没有明确的定义(有时就像“闲逛”一样简单),如果一些代码已经进入了一个“杂项”主题,那么根据上面的问题,它就不能再从那里取出来了?你如何定义/批准/毕业/发布你的主题分支?< / p >

    • 适当的程序,如代码审查和毕业当然是可爱的。

      但是我们根本无法把事情弄得足够清楚来处理这个问题——有什么建议吗? 集成分支、插图?李< / p > < / >

以下是相关问题:

也看看塑料SCM在任务驱动开发上写了什么,如果塑料不是你的选择,研究Nvie的分支模型和他的支持脚本

73863 次浏览

DVCS的新开发者需要意识到的最麻烦的特性是出版的过程:

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

因此,你可以遵循一些规则来让你的问题更简单:

现在:

工作流/分支模型:

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

只有“集成商”才应该在“中央”回购上建立正式的功能分支,然后开发人员可以获取这些分支,以重新调整/合并适合该功能的部分工作。

合并vs重基(纠缠vs顺序历史):

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

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

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

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

正如他的回答中的Jakub Narębski所述,樱桃选择应该保留在需要的罕见情况下 如果你的设置涉及到大量的挑选(即。

. "it is not rare"),那么就有什么东西掉了

应用相同的提交是否会恢复(如何做到这一点?)

git revert应该照顾这一点,但这不是理想的。

如何分解成局部分支?

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

  • 如果需要,有几个分支(其中一个由明确识别的特性组成)
  • 一个分支中的一组连贯的提交(参见删除Git检查)

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

集成分支(在专用集成中)回购可以帮助开发人员:

  • 将他/她的开发基于远程集成分支之上(pull—Rebase)
  • 在当地解决
  • 推动开发到回购
  • 与积分器检查,不会导致混乱;)

我认为,我可能是错的,关于git最容易被误解的事情之一是它的分布式特性。这使得在您可以工作的方式上说颠覆是非常不同的,尽管您可以模仿SVN的行为,如果您愿意的话。问题是几乎任何工作流程都可以,这很好,但也会误导人。

如果我对内核开发有正确的理解(我将重点讨论这一点),那么每个人都有自己的git存储库来开发内核。有一个存储库,linux-2.6。git,由Torvalds管理,它充当发行版存储库。如果人们希望开始针对“发布”分支开发一个特性,就可以从这里克隆。

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

这就是让人困惑的地方。分支名称根本不需要在存储库之间保持一致。因此,我可以git pull origin master:vanilla-code并从我的存储库中名为vanilla-code的分支中的origin的主分支中获得一个分支。如果我知道发生了什么,这真的无关紧要——它是分布式的,因为所有存储库都是彼此对等的,而不是像SVN那样在多台计算机之间共享。

所以,考虑到这些:

  1. 我认为这取决于每个程序员如何进行分支。你所需要的只是一个管理版本的中央存储库等等。Trunk可以是head。发行版可以是标签或者分支,而热修复本身可能就是分支。事实上,我可能会把发布作为分支,这样你就可以不断地修补它们。
  2. 我会合并,而不是重组。例如,如果你使用一个存储库,克隆它,分支并做一些开发,然后从你的origin中提取,你应该在存储库中创建另一个分支,并将最新的master合并到yourbranch中,这样其他人就可以尽可能少地提取你的更改。根据我的经验,很少有必要真正地调整基地。
  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那样“分层”。本质上,每个人都有提交访问权,但仅限于本地。它是对存储库的访问权,以及您将哪个存储库指定为发布回购,从而允许您使用层次结构。

我使用过的一个效果不错的模型如下:

一个“受祝福的”回购,每个人都推或拉到/从,基本上是一个客户机-服务器拓扑。

没有主分支,所以没有开发人员可以将任何代码推入“主线”。

所有的开发都发生在主题分支上。我们对名称进行命名空间,以便轻松检测谁负责:jn/newFeature或jn/issue-1234

分支和白板上的看板/scrum卡之间也有接近1对1的映射。

为了释放一个分支,它被推到被祝福的回购,看板卡被移动到准备审查。

然后,如果这个分支被评审所接受,那么它就是一个发布的候选。

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

通过将新标签推到受祝福的repo,就有了一个新的可能的新特性基础。

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

就我个人而言,我尽量只在主分支中保留发布就绪的代码。

当我开发一个新特性或修复bug时,我会在分支中进行。我还在分支中进行单元测试。如果一切顺利,只有这样我才合并/rebase回主。

我也尝试使用通用分支命名约定,比如:

  • 错误修复/ recursive_loop
  • 错误修复/ sql_timeout
  • 特性/ new_layout
  • 特性/ enhanced_search