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

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? gitworkflows(7) Manual Page (nvie) A successful Git branching model (reinh) A Git Workflow for Agile Teams Merging vs rebasing (tangled vs sequential history) Should one pull --rebase or 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-ff for 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). 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 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. 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? Proper procedures like code review and graduating would of course be lovely. But we simply cannot keep things untangled enough to manage this - any suggestions? integration branches, illustrations?

以下是相关问题:

What are some good strategies to allow deployed applications to be hotfixable? Workflow description for Git usage for in-house development Git workflow for corporate Linux kernel development How do you maintain development code and production code? (thanks for this PDF!) git releases management Git Cherry-pick vs Merge Workflow How to cherry-pick multiple commits How do you merge selective files with git-merge? How to cherry pick a range of commits and merge into another branch ReinH Git Workflow git workflow for making modifications you’ll never push back to origin Cherry-pick a merge Proper Git workflow for combined OS and Private code? Maintaining Project with Git Why cant Git merge file changes with a modified parent/master. Git branching / rebasing good practices When will "git pull --rebase" get me in to trouble? How are DVCS used in large teams?

还可以看看Plastic SCM在任务驱动开发方面写了什么,如果你不选择Plastic,可以研究一下nvie的分支模型和它的支持脚本。


当前回答

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

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

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

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

所以,考虑到这些:

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. I would merge and not rebase. If for example you take a repository, clone it, branch and do some dev, then pull from your origin you should, in your repository, probably make another branch and merge the latest master into yourbranch so 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. 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. 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. 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. This is the merge stage. You only merge into release branches etc when you consider code to be reviewed/pass quality testing.

我希望这对你有所帮助。我意识到VonC刚刚发布了一个非常相似的解释…我打得不够快!

编辑一些关于如何在商业环境中使用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.

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-ui so he does git checkout latest-ui followed 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-latest branches 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.

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

其他回答

DVCS的新开发人员需要认识到的最麻烦的特性是发布过程:

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

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

只在分支没有被推送的情况下才对其进行重基(自上次重基后就没有推送过) 只推到裸回购(从Git1.7开始强制) 遵循李纳斯的建议,重新编制和合并

Now:

工作流/分支模型:

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"),...

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

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

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

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

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

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

正如Jakub narabbski在他的回答中所述,应该在需要的罕见情况下进行挑选。 如果你的设置涉及到大量的挑选(即。“这并不罕见”),那么就有问题了。

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

Git恢复应该会处理这个问题,但这并不理想。

如何分解成局部分支?

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

如果需要,有几个分支(其中一个由明确识别的特性组成) 一个分支内的一组连贯的提交(参见修剪Git checkin)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

所以,考虑到这些:

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. I would merge and not rebase. If for example you take a repository, clone it, branch and do some dev, then pull from your origin you should, in your repository, probably make another branch and merge the latest master into yourbranch so 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. 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. 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. 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. This is the merge stage. You only merge into release branches etc when you consider code to be reviewed/pass quality testing.

我希望这对你有所帮助。我意识到VonC刚刚发布了一个非常相似的解释…我打得不够快!

编辑一些关于如何在商业环境中使用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.

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-ui so he does git checkout latest-ui followed 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-latest branches 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.

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

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

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

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

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