关于合并:Git分支模型适合您?

What Git branching models work for you?

我们公司目前使用的是一个简单的主干/发布/修复程序分支模型,并且希望得到关于什么分支模型最适合您的公司或开发过程的建议。

  • 工作流/分支模型

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

    • GitWorkflows(7)手册页
    • (NVIE)成功的Git分支模型
    • (reinh)敏捷团队的Git工作流
  • 合并与重新平衡(纠结与连续历史)

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

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

    有时,错误会发生,因为我们的程序不能用简单的规则捕获特定的情况。例如,早期版本所需的修复应该足够基于下游,以便能够将上游合并到所有必要的分支(这些术语的用法是否足够清楚?)但是,在开发人员意识到应该将其放在下游更远处之前,修复程序会使其进入主程序,如果已经被推送(更糟的是,合并或基于它的某些内容),则剩余的选项是挑选樱桃,并伴随着相关的危险。你使用什么样的简单规则?此外,其中还包括一个主题分支的笨拙,这必然会排除其他主题分支(假设它们是从公共基线分支的)。开发人员不想完成一个特性来启动另一个特性,感觉他们刚刚编写的代码已经不存在了。

  • 如何避免创建合并冲突(由于cherry pick)?

    创建合并冲突的一个可靠方法似乎是在分支之间进行挑选,它们再也不能合并了?是否在Revert中应用相同的提交(如何执行此操作?)在任何一个分支都有可能解决这个问题?这就是我不敢推动一个基本上基于合并的工作流的原因之一。

  • 如何分解成局部分支?

    我们意识到,从主题分支组装一个完成的集成是非常棒的,但是我们的开发人员的工作常常没有明确的定义(有时简单到"四处搜索"),并且如果一些代码已经进入了"杂项"主题,那么它就不能再被带出,根据上面的问题?如何定义/批准/毕业/发布主题分支?

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

    但是我们不能把事情搞得一团糟来解决这个问题——有什么建议吗?集成分支,插图?

  • 以下是相关问题的列表:

    • 什么是允许部署的应用程序可热修复的好策略?
    • 用于内部开发的Git使用的工作流说明
    • 企业Linux内核开发的Git工作流
    • 如何维护开发代码和生产代码?(感谢您提供此PDF!)
    • Git发布管理
    • Git Cherry选择与合并工作流
    • 如何选择多个提交
    • 如何将选择性文件与Git合并合并?
    • 如何挑选一系列提交并合并到另一个分支
    • 重新生成Git工作流
    • 用于进行修改的Git工作流永远不会推回到源站
    • Cherry选择合并
    • 联合操作系统和私有代码的适当Git工作流?
    • 使用Git维护项目
    • 为什么不能将文件更改与修改后的父/主文件合并。
    • Git分支/再平衡良好实践
    • 什么时候"吉特拉--再平衡"会让我陷入麻烦?
    • 如何在大型团队中使用DVC?

    另外,看看Plastic SCM在任务驱动的开发上写了什么,如果您不选择Plastic,请研究Nvie的分支模型和支持脚本。


    新开发人员需要了解的最麻烦的功能是发布过程:

    • 您可以导入(提取/提取)所需的任何远程报告
    • 您可以发布(推送)到您想要的任何(裸)回购。

    从这一点上,您可以遵守一些规则,使您的问题更容易处理:

    • 仅当分支未被推送时(自上一次推送后未被推送),才重新对其进行调整。
    • 仅推动进行裸回购(自git1.7起强制执行)
    • 遵循Linus关于Rebase和Merges的建议

    现在:

    工作流/分支模型:

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

    只有"集成商"才应该在"中央"回购协议上建立官方的功能分支,然后开发人员可以提取这些分支来重新平衡/合并他们的工作中符合该功能的部分。

    合并与重新平衡(纠结与顺序历史):

    我喜欢你提到的我的答案("内部开发中Git使用的工作流描述")。

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

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

    如何避免创建合并冲突(由于cherry pick)?

    如Jakub Nar所述?bski在他的回答中,樱桃采摘应该被保留在罕见的情况下。如果你的设置涉及到大量的樱桃采摘(即"并不罕见"),那么就会出现问题。

    Would applying the same commit in revert (how to do this?)

    git revert应该处理好这一点,但这并不理想。

    How to decompose into topical branches?

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

    • 如果需要的话,几个分支(一个接一个的明确识别特征)
    • 一个分支内一致的提交集(请参见剪裁Git签入)

    正确的程序,如代码审查和毕业?

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

    • 在远程集成分支的基础上重新平衡他/她的开发(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的分支中。如果我知道发生了什么,那就真的不重要了——它是分布式的,从某种意义上说,所有的存储库都是彼此对等的,而不仅仅是在像SVN这样的多台计算机上共享。好的。

    因此,考虑到所有这些:好的。

  • 我认为这取决于每个程序员如何进行分支。您只需要一个用于管理发布等的中央存储库。主干可以是head。发布可能是标记或分支,而修补程序可能本身就是分支。实际上,我可能会以分支的形式进行发布,这样您就可以继续修补它们了。
  • 我会合并而不是重新平衡。例如,如果您获取一个存储库,克隆它,分支并进行一些开发,然后从您的origin中提取,那么您应该在存储库中创建另一个分支并将最新的master合并到yourbranch中,以便其他人尽可能少地提取您的更改。根据我的经验,几乎没有必要真正重新平衡。
  • 我认为这是一个理解Git工作方式和它能做什么的案例。这确实需要一段时间和大量良好的沟通-我只是真正开始了解当我开始与其他开发人员一起使用Git时发生了什么,甚至现在,一些我不确定的事情。
  • 合并冲突很有用。我知道,我知道,你希望一切都能正常工作,但事实上,代码发生了变化,你确实需要把结果合并成一些有用的东西。合并冲突实际上只是更多的编程。我从来没有找到一个简单的解释来解释如何处理它们,所以这里是:注意那些有合并冲突的文件,把它们改成它们应该是的,git add .,然后git commit
  • 不管它适合什么。正如我所说,每个用户git存储库都是他们自己玩的,分支名称不需要相同。例如,如果您有一个临时存储库,您可以强制执行一个命名模式,但是对于每个开发人员,您不需要这样做,只需要在发行版repo中。
  • 这是合并阶段。只有当您考虑要审查/通过质量测试的代码时,才合并到发布分支等中。
  • 希望有帮助。我意识到VONC发布了一个非常相似的解释…我打字速度不够快!好的。

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

    • 我们称之为product.git的发行版存储库,可供一些高级程序员/技术人员访问,他们负责实际维护产品本身。它们类似于OSS中维护者的角色。
    • 这些程序员可能也在一定程度上领导新版本的开发,因此他们也可能自己编写代码并维护各种存储库。他们可能会为真正的新功能管理登台存储库,也可能有自己的存储库。
    • 下面是负责开发单个位的程序员。例如,可能有人负责UI工作。因此,它们管理ui.git存储库。
    • 下面是实际的程序员,他们将这些特性作为他们的日常工作来开发。

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

    它不是一种"传统"的工作方式,设计为"对等驱动",而不是像SVN/CVS那样的"层次"。本质上,每个人都有提交访问权,但只能在本地进行。它是对存储库的访问,以及指定哪个存储库作为发行版repo,从而允许您使用层次结构。好的。好啊。


    我使用的一个具有良好效果的模型如下:

    一个"幸运的"回购,每个人推拉到/从,基本上是一个客户机-服务器拓扑。

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

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

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

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

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

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

    通过将新标签推到受祝福的回购上,可以为新功能提供新的可能基础。

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


    就我个人而言,我尝试在主分支中只保留准备好发布的代码。

    当我处理一个新特性或错误修复时,我会在一个分支中这样做。我也在分支机构进行单元测试。如果一切正常,只有这样我才能合并/重新设置主控形状。

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

    • 错误修复/递归循环
    • 错误修复/sql_超时
    • 功能/新布局
    • 功能/增强型搜索