哪些 Git 分支模型适合您?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2621610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 08:14:12  来源:igfitidea点击:

What Git branching models work for you?

gitmergeworkflowreleasecherry-pick

提问by HiQ CJ

Our company is currently using a simple trunk/release/hotfixes branching model and would like advice on what branching models work best for your company or development process.

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

  1. Workflows / branching models

    Below are the three main descriptions of this I have seen, but they are partially contradicting each other or don't go far enough to sort out the subsequent issues we've run into (as described below). Thus our team so far defaults to not so great solutions. Are you doing something better?

  2. Merging vs rebasing (tangled vs sequential history)

    Should one pull --rebaseor wait with merging back to the mainline until your task is finished? Personally I lean towards merging since this preserves a visual illustration of on which base a task was started and finished, and I even prefer merge --no-fffor this purpose. It has other drawbacks however. Also many haven't realized the useful property of merging - that it isn't commutative(merging a topic branch into master does not mean merging master into the topic branch).

  3. I am looking for a natural workflow

    Sometimes mistakes happen because our procedures don't capture a specific situation with simple rules. For example a fix needed for earlier releases should of course be based sufficiently downstream to be possible to merge upstream into all branches necessary (is the usage of these terms clear enough?). However it happens that a fix makes it into the master before the developer realizes it should have been placed further downstream, and if that is already pushed (even worse, merged or something based on it) then the option remaining is cherry-picking, with its associated perils. What simple rules like such do you use? Also in this is included the awkwardness of one topic branch necessarily excluding other topic branches (assuming they are branched from a common baseline). Developers don't want to finish a feature to start another one feeling like the code they just wrote is not there anymore

  4. How to avoid creating merge conflicts (due to cherry-pick)?

    What seems like a sure way to create a merge conflict is to cherry-pick between branches, they can never be merged again? Would applying the same commit in revert (how to do this?) in either branch possibly solve this situation? This is one reason I do not dare to push for a largely merge-based workflow.

  5. How to decompose into topical branches?

    We realize that it would be awesome to assemble a finished integration from topic branches, but often work by our developers is not clearly defined (sometimes as simple as "poking around") and if some code has already gone into a "misc" topic, it can not be taken out of there again, according to the question above? How do you work with defining/approving/graduating/releasing your topic branches?

  6. Proper procedures like code review and graduatingwould of course be lovely.

    But we simply cannot keep things untangled enough to manage this - any suggestions? integration branches, illustrations?

  1. 工作流/分支模型

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

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

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

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

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

  4. 如何避免产生合并冲突(由于挑选)?

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

  5. 如何分解为主题分支?

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

  6. 代码和毕业等适当的程序当然会很可爱。

    但是我们根本无法保持足够的混乱来管理这个 - 有什么建议吗?集成分支,插图?

Below is a list of related questions:

以下是相关问题的列表:

Also check out what Plastic SCM writes on task driven development, and if Plastic is not your choice, study nvie's branching modeland his supporting scripts.

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

采纳答案by VonC

The most troubling feature new developers to DVCS need to realize is about the publication process:

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

  • you can import (fetch/pull) whatever remote repo you need
  • you can publish (push) to any (bare) repo you want
  • 你可以导入(获取/拉取)你需要的任何远程仓库
  • 您可以发布(推送)到您想要的任何(裸)存储库

From that, you can respect a few rules to make your questions easier:

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

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

Now:

现在:

Workflows / branching models:

工作流/分支模型

each workflow is there to support a release management process, and that is tailored for each project.
What I can add to the workflow you mention is: each developer should not create a feature branch, only a "current dev" branch, because the truth is: the developer often doesn't know what exactly his/her branch will produce: one feature, several (because it ended up being too complex a feature), none (because not ready in time for release), another feature (because the original one had "morphed"),...

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

Only an "integrator" should established official feature branches on a "central" repo, which can then be fetched by developers to rebase/merge the part of their work that fits that feature.

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

Merging vs rebasing (tangled vs sequential history):

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

I like my answer you mention ("Workflow description for git usage for in-house development")

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

I am looking for a natural workflow:

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

for fixes, it can help associating each fix with a ticket from a bug tracking, which helps the developer remember where (i.e. on which branch, i.e. a dedicated branch "for fixes") he/she should commit such modifications.
Then hooks can help protect a central repo against pushes from non-validated bug-fixes or from branches from which one shouldn't push. (no specific solution here, all this need to be adapted to your environment)

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

How to avoid creating merge conflicts (due to cherry-pick)?

如何避免产生合并冲突(由于挑选)?

As stated by Jakub Nar?bskiin his answer, cherry-picking should be reserved for rare situations where it is required.
If your setup involves a lot of cherry-picking (i.e. "it is not rare"), then something is off.

正如Jakub Nar?bski他的回答中所说,樱桃采摘应该保留在需要它的罕见情况下。
如果您的设置涉及大量的樱桃采摘(即“这并不罕见”),那么就有些不对劲了。

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

是否会在还原中应用相同的提交(如何执行此操作?)

git revertshould take care of that, but that is not ideal.

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

How to decompose into topical branches?

如何分解为主题分支?

As long as a branch as not yet been pushed everywhere, a developer should reorganize its history of commits (once he/she finally see the development takes a more definitive and stable shape) into:

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

  • several branches if needed (one by clear identified feature)
  • a coherent set of commits within one branch (see Trimming Git Checkins)
  • 如果需要,有几个分支(一个通过明确识别的特征)
  • 一个分支内的一组连贯提交(请参阅修剪 Git 签入

Proper procedures like code review and graduating ?

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

Integration branches (in a dedicated integration) repo can help the developer to:

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

  • rebase his/her development on top of that remote integration branch (pull --rebase)
  • solve locally
  • push the development to that repo
  • check with the integrator that doesn't result in a mess ;)
  • 在该远程集成分支之上重新构建他/她的开发(pull --rebase)
  • 本地解决
  • 推动开发到该回购
  • 与不会导致混乱的集成商核对 ;)

回答by VonC

I think, and I might be wrong, that one of the things that's most misunderstood about git is its distributed nature. This makes it very different to say subversion in the ways you can work although you can mimick SVN behaviour should you want. The problem is pretty much any workflow will do, which is great but also misleading.

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

If I have my understanding of kernel development (I'll focus on that) right, everyone has their own git repository for developing the kernel. There is one repository, linux-2.6.git, looked after by Torvalds, that acts as the release repository. People clone from here if they wish to start developing a feature against the "release" branch.

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

Other repositories do some development. The idea is to clone from linux-2.6, branch out as many times as you like until such a point as you've got a working "new" feature. Then, when this is ready, you may make it available to someone considered trusted, who will pull this branch from your repository into theirs and merge it into the mainstream. In the linux kernel this happens on several levels (trusted lieutenants) until it reaches linux-2.6.git at which point it becomes "the kernel".

其他存储库做一些开发。这个想法是从 linux-2.6 克隆,尽可能多地分支,直到你有一个可用的“新”功能。然后,当它准备好时,您可以将其提供给被认为是可信的人,他们将从您的存储库中将此分支拉入他们的存储库并将其合并到主流中。在 linux 内核中,这发生在几个级别(受信任的副手),直到它到达 linux-2.6.git,此时它成为“内核”。

Now here's where it gets confusing. Branch names don't need to be consistent across repositories at all. So I can git pull origin master:vanilla-codeand get a branch from the origin's master in a branch in my repository called vanilla-code. Providing I know what's going on, it really doesn't matter - it is distributed in the sense that all repositories are peers to each other and not just shared across several computers like SVN.

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

So, with all of this in mind:

因此,考虑到所有这些:

  1. I think it is up to each programmer how they do their branching. All you need is a central repository for managing releases etc. Trunk could be head. Releases could be tags or branches and hotfixes are probably branches in themselves. In fact, I'd probably do releases as branches so you can keep patching them.
  2. I would merge and not rebase. If for example you take a repository, clone it, branch and do some dev, then pull from your originyou should, in your repository, probably make another branch and merge the latest masterinto yourbranchso that someone else can pull your changes with as little effort as possible. There is very rarely a need to truly rebase, in my experience.
  3. I think it's a case of understanding the way Git works and what it can do. It does take a while and a lot of good communication - I only truly started to understand what's going on when I began using git with other developers and even now, some things I'm not sure about.
  4. Merge conflicts are useful. I know, I know, you want it all to work, but, the fact is code changes and you do need to merge the results into something that works. Merge conflicts are in fact just more programming. I've never found an easy explanation for what to do about them, so here it is: note the files that have merge conflicts, go and change them to what they should be, git add .and then git commit.
  5. However it suits. As I've said, each users git repository is their own to play with and branch names don't need to be the same. If you had a staging repository, for example, you could enforce a naming schema, but you don't need to for each developer, only in the release repo.
  6. This is the merge stage. You only merge into release branches etc when you consider code to be reviewed/pass quality testing.
  1. 我认为这取决于每个程序员如何进行分支。您所需要的只是一个用于管理发布等的中央存储库。Trunk 可以是head. 发布可能是标签或分支,修补程序本身可能是分支。事实上,我可能会以分支的形式发布,这样你就可以继续修补它们。
  2. 我会合并而不是变基。例如,如果您获取一个存储库,克隆它,分支并进行一些开发,然后从您origin的存储库中拉取,您应该在您的存储库中创建另一个分支并将最新的合并master到其中,yourbranch以便其他人可以毫不费力地拉取您的更改可能的。根据我的经验,很少需要真正变基。
  3. 我认为这是理解 Git 的工作方式及其能做什么的一个案例。这确实需要一段时间和很多良好的沟通 - 当我开始与其他开发人员一起使用 git 时,我才真正开始了解发生了什么,即使是现在,有些事情我也不确定。
  4. 合并冲突很有用。我知道,我知道,您希望这一切都能正常工作,但是,事实是代码发生了变化,您确实需要将结果合并为有效的内容。合并冲突实际上只是更多的编程。我从来没有找到一个简单的解释来说明如何处理它们,所以这里是:注意有合并冲突的文件,将它们更改为它们应该是的,git add .然后git commit.
  5. 不过很适合。正如我所说,每个用户的 git 存储库都是他们自己的,分支名称不需要相同。例如,如果您有一个临时存储库,您可以强制实施命名模式,但您不需要为每个开发人员强制执行,只需在发布存储库中即可。
  6. 这是合并阶段。当您考虑要/通过质量测试的代码时,您只会合并到发布分支等。

I hope that helps. I realise VonC as just posted a very similar explanation... I can't type fast enough!

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

Editsome further thoughts on how to use git in a commercial setting, as this seems relevant to the OP from the comments:

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

  • The release repository, we'll call it product.git, is accessible by a number of senior programmers / technical people responsible for actually looking after the product itself. They are analogous to the role of maintainers in OSS.
  • These programmers probably also in part lead development of new versions, so they might also code themselves and maintain varios repositories. They might manage staging repositories for really new features and they might also have their own repositories.
  • Below them are programmers responsible for developing individual bits. For example, someone might be responsible for the UI work. They therefore manage the UI.git repository.
  • Below them are the actual programmers who develop the features as their full day to day job.
  • 发布存储库,我们称之为product.git,可供许多负责实际管理产品本身的高级程序员/技术人员访问。它们类似于 OSS 中维护者的角色。
  • 这些程序员可能还部分领导新版本的开发,因此他们也可能自己编写代码并维护各种存储库。他们可能会管理真正新功能的临时存储库,他们也可能拥有自己的存储库。
  • 在他们下面是负责开发单个位的程序员。例如,有人可能负责 UI 工作。因此,他们管理 UI.git 存储库。
  • 在他们下面是实际的程序员,他们将这些功能作为他们的日常工作来开发。

So what happens? Well, everyone pulls at the start of each day from the "upstream" source i.e. the release repository (which will also probably contain the latest material from the previous days development). Everyone does this, directly. This will go on a branch in their repository, probably called "master" or maybe if you're me called "latest". The programmer will then do some work. This work might be something they're not sure about, so they make a branch, do the work. If it doesn't work, they can delete the branch and go back. If it does, they will have to merge into the main branch they're currently working on. We'll say this is a UI programmer working on latest-uiso he does git checkout latest-uifollowed by git merge abc-ui-mywhizzynewfeature. He then tells his technical lead (the UI lead) hey, I've completed such a task, pull from me. So the UI lead does git pull user-repo lastest-ui:lastest-ui-suchafeature-abc. The UI lead then looks at it on that branch and says, actually, that's very good, I'll merge it into ui-latest. He might then tell everyone below him to pull from him on their ui-latestbranches or whatever name they've given them, and so the feature gets explored by the devs. If the team is happy, the UI lead might ask the testing lead to pull from him and merge the changes. This propagates out to everyone (downstream of the change) who tests it and submits bug reports etc. Finally, if the feature passes testing etc, one of the top technical leads might merge it into the current working copy of the program, at which point all the changes are then propagated back down. And so on.

那么会发生什么?好吧,每个人在每天开始时都从“上游”源即发布存储库(其中也可能包含前几天开发的最新材料)中提取。每个人都这样做,直接。这将在他们的存储库中的一个分支上进行,可能称为“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 负责人可能会要求测试负责人从他那里提取并合并更改。这会传播给测试它并提交错误报告等的每个人(更改的下游)。 最后,如果该功能通过测试等,顶级技术负责人之一可能会将其合并到程序的当前工作副本中,此时然后将所有更改向下传播。等等。

It's not a "traditional" way of working and is designed to be "peer driven" rather than "hierarchical" like SVN/CVS. In essence, everyone has commit access, but only locally. It is access to the repository and which repository you designate as the release repo that allows you to use hierarchy.

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

回答by John Nilsson

A model that I've used with good results is the following:

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

A "blessed" repo everybody pushes and pulls to/from, basically a client-server topology.

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

There's no master branch so no developer can push any code into "mainline".

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

All developments happen on topic branches. We namespaced names to easily detect who is responsible for it: jn/newFeature or jn/issue-1234

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

There is also a near 1-to-1 mapping between branches and kanban/scrum cards on the whiteboard.

白板上的分支机构和看板/Scrum 卡之间也有近乎一对一的映射。

To release a branch it is pushed to the blessed repo and the kanban-card is moved to ready for review.

为了发布一个分支,它被推送到有福的仓库,看板卡被移动到准备。

Then, if the branch is accepted by the review, it is a candidate for a release.

然后,如果该分支被接受,则它是发布的候选者。

A release happens when a set of accepted branches are merged together and tagged with a version number.

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

By pushing the new tag to the blessed repo there is a new possible base for new features.

通过将新标签推送到受祝福的 repo,为新功能提供了一个新的可能基础。

To avoid merge conflicts developers are kindly requested to update (merge) their unreleased branches to the latest release tag.

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

回答by xero

Personally, I try and keep only release-ready code in the master branch.

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

When I work on a new feature or bugfix I do that in a branch. I also unit-test in the branch. If everything works out OK, only then do I merge/rebase back into master.

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

I try and use common branch naming conventions as well, such as:

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

  • bugfix/recursive_loop
  • bugfix/sql_timeout
  • feature/new_layout
  • feature/enhanced_search
  • 错误修正/recursive_loop
  • 错误修正/sql_timeout
  • 功能/新布局
  • 功能/增强_搜索