哪些 Git 分支模型适合您?
我们公司目前正在使用简单的主干/发布/修补程序分支模型,并且希望了解哪些分支模型最适合您的公司或开发流程。
工作流程/分支模型
下面是我看到的对此的三个主要描述,但它们部分相互矛盾,或者不足以解决我们遇到的后续问题(如下所述)。因此,我们的团队到目前为止默认的解决方案并不是那么好。你在做更好的事情吗?
合并与变基(纠结与顺序历史)< /强>
应该
pull --rebase
还是等待合并回主线,直到任务完成?就我个人而言,我倾向于合并,因为这保留了任务开始和完成的视觉说明,为此我什至更喜欢使用merge --no-ff
。然而它还有其他缺点。此外,许多人还没有意识到合并的有用属性 - 它不是可交换的(合并一个主题分支到 master 并不意味着将 master 合并到主题分支)。我正在寻找自然的工作流程
有时会发生错误,因为我们的程序没有用简单的规则捕获特定的情况。例如,早期版本所需的修复当然应该充分基于下游,以便可以将上游合并到所有必要的分支中(这些术语的用法是否足够清晰?)。然而,在开发人员意识到它应该被放置在更下游之前,修复程序就会进入主版本,如果它已经被推送(更糟糕的是,合并或基于它的东西),那么剩下的选项就是精挑细选,其相关的危险。您使用什么简单的规则? 这还包括一个主题分支必然排除其他主题分支(假设它们是从公共基线分支出来的)的尴尬。开发人员不想完成一项功能来启动另一项功能,感觉他们刚刚编写的代码已经不存在了
如何避免创建合并冲突(由于cherry-pick)?强>
似乎造成合并冲突的可靠方法是在分支之间进行挑选,它们永远不能再次合并?在任一分支中应用相同的提交来恢复(如何执行此操作?)是否可以解决这种情况?这是我不敢推动很大程度上基于合并的工作流程的原因之一。
如何分解为主题分支?
我们意识到,从主题分支组装完成的集成会很棒,但我们的开发人员的工作通常没有明确定义(有时就像“四处探索”一样简单),并且如果某些代码已经进入“杂项” ” 话题,根据上面的问题,不能再从那里取出来了吗?您如何定义/批准/毕业/发布您的主题分支?
像代码审查和毕业这样的适当程序当然会很可爱。
但我们根本无法让事情变得足够理顺来管理这个问题 - 有什么建议吗? 集成分支、插图?
以下是相关问题的列表:
- 有哪些好的策略可以允许已部署的应用程序进行热修复?
- 内部开发的 Git 使用工作流程描述
- 用于企业 Linux 内核开发的 Git 工作流程
- 如何维护开发代码和生产代码?(感谢 此 PDF!)
- git 版本管理
- Git Cherry-pick 与合并工作流程
- 如何樱桃-pick 多个提交
- 如何合并选择性文件使用 git-merge?
- 如何挑选一系列提交并合并到另一个分支
- ReinH Git 工作流程
- git 工作流程,用于进行你永远不会做的修改推回原点
- 择优选择合并
- 组合操作系统和私有代码的正确 Git 工作流程?
- 使用 Git 维护项目
- 为什么 Git 无法将文件更改与修改后的父级/主控合并。
- Git 分支/变基良好实践
- “git pull --rebase”什么时候会给我带来麻烦?
- DVCS 在大型团队中如何使用?
另请查看 Plastic SCM 在 任务驱动开发,如果 Plastic 不是您的选择,请学习 nvie 的分支模型 及其支持脚本。
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.
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?
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 prefermerge --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?
Below is a list of related questions:
- 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?
Also check out what Plastic SCM writes on task driven development, and if Plastic is not your choice, study nvie's branching model and his supporting scripts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
DVCS 新开发人员需要实现的最麻烦的功能是关于 发布过程:
从此,您可以遵守一些规则让你的问题变得更简单:
现在:
工作流程/分支模型:
每个工作流程是为了支持发布管理流程,并且是针对每个项目量身定制的。
我可以添加到您提到的工作流程中的是:每个开发人员不应该创建一个功能分支,而只能创建一个“当前开发”分支,因为事实是:开发人员通常不知道他/她的分支到底会产生什么:一个功能,几个(因为它最终是一个过于复杂的功能),没有(因为没有及时准备好发布),另一个功能(因为原始功能已经“变形”),...
只有一个“集成商”应该建立官方“中央”存储库上的功能分支,然后开发人员可以获取这些分支来重新调整/合并适合该功能的工作部分。
合并与变基(纠结与顺序历史):
我喜欢你提到的我的答案(“内部开发的 git 使用的工作流程描述")
我正在寻找一个自然的工作流程:
对于修复,它可以提供帮助将每个修复与错误跟踪中的票证相关联,这有助于开发人员记住他/她应该在哪里(即在哪个分支上,即“用于修复”的专用分支)提交此类修改。
然后,钩子可以帮助保护中央存储库免受未经验证的错误修复或不应推送的分支的推送。 (这里没有具体的解决方案,所有这些都需要适应您的环境)
如何避免创建合并冲突(由于cherry-pick)?
如Jakub Narębski 在 他的回答,挑选樱桃应该保留在极少数需要的情况下。
如果你的设置涉及大量的挑选(即“这并不罕见”),那么有些事情就不对劲了。
git revert
应该解决这个问题,但这并不理想。只要分支尚未被推送到任何地方,开发人员就应该将其提交历史记录(一旦他/她最终看到开发采取更明确和稳定的形式)重新组织为:
正确代码审查和毕业等程序?
集成分支(在专用集成中)存储库可以帮助开发人员:
The most troubling feature new developers to DVCS need to realize is about the publication process:
From that, you can respect a few rules to make your questions easier:
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):
I like my answer you mention ("Workflow description for git usage for in-house development")
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ębski in 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.
git revert
should take care of that, but that is not ideal.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:
Proper procedures like code review and graduating ?
Integration branches (in a dedicated integration) repo can help the developer to:
我认为,关于 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
的 master 获取一个分支代码>.只要我知道发生了什么,这真的不重要 - 它是分布式的,所有存储库都是对等的,而不仅仅是像 SVN 那样在多台计算机上共享。因此,考虑到所有这些:
head
。发布可以是标签或分支,而修补程序本身可能就是分支。事实上,我可能会以分支的形式发布版本,这样你就可以继续修补它们。origin
中提取,您应该在您的存储库中创建另一个分支并合并最新的master 到
yourbranch
中,以便其他人可以尽可能轻松地拉取您的更改。根据我的经验,很少需要真正重新设置基准。git add .
,然后git 提交
。我希望这有帮助。我意识到 VonC 刚刚发布了一个非常相似的解释......我打字速度不够快!
编辑关于如何在商业环境中使用 git 的一些进一步的想法,因为这似乎与评论中的OP相关:
product.git
,可由许多负责实际管理产品本身的高级程序员/技术人员访问。他们类似于 OSS 中维护者的角色。那么会发生什么呢?好吧,每个人每天开始时都会从“上游”源(即发布存储库)中提取内容(其中也可能包含前几天开发的最新材料)。每个人都直接这样做。这将在他们的存储库中的一个分支上进行,可能称为“master”,或者如果你是我,则可能称为“latest”。然后程序员将做一些工作。这项工作可能是他们不确定的事情,所以他们创建一个分支,来做这项工作。如果不起作用,他们可以删除该分支并返回。如果确实如此,他们将不得不合并到他们当前正在处理的主分支中。我们会说这是一位正在开发
latest-ui
的 UI 程序员,因此他执行git checkoutlatest-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 那样的“分层”。本质上,每个人都具有提交访问权限,但仅限于本地。它是对存储库的访问以及您将哪个存储库指定为允许您使用层次结构的发布存储库。
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.
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.
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".
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-code
and get a branch from theorigin
's master in a branch in my repository calledvanilla-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.So, with all of this in mind:
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.origin
you should, in your repository, probably make another branch and merge the latestmaster
intoyourbranch
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.git add .
and thengit commit
.I hope that helps. I realise VonC as just posted a very similar explanation... I can't type fast enough!
Edit some further thoughts on how to use git in a commercial setting, as this seems relevant to the OP from the comments:
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.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 doesgit checkout latest-ui
followed bygit 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 doesgit 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 intoui-latest
. He might then tell everyone below him to pull from him on theirui-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.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.
我使用过并取得良好效果的模型如下:
每个人都可以推送和拉取的“有福的”存储库,基本上是客户端-服务器拓扑。
没有主分支,因此没有开发人员可以将任何代码推送到“主线”中。
所有的进展都发生在主题分支上。我们对名称进行了命名,以便轻松检测谁负责:jn/newFeature 或 jn/issue-1234
白板上的分支和看板/scrum 卡之间也有近乎 1 对 1 的映射。
为了发布分支,它被推送到受祝福的存储库,并且看板卡被移至准备审查状态。
然后,如果该分支通过审查,则它是发布的候选者。
当一组接受的分支合并在一起并用版本号标记时,就会发生发布。
通过将新标签推送到受祝福的存储库,新功能就有了一个新的可能基础。
为了避免合并冲突,恳请开发人员将其未发布的分支更新(合并)到最新的发布标签。
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
There is also a near 1-to-1 mapping between branches and kanban/scrum cards on the whiteboard.
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.
To avoid merge conflicts developers are kindly requested to update (merge) their unreleased branches to the latest release tag.
就我个人而言,我尝试只在主分支中保留可发布的代码。
当我开发新功能或修复错误时,我会在分支中进行。我还在分支进行单元测试。如果一切顺利,只有这样我才会合并/变基回master。
我也尝试使用常见的分支命名约定,例如:
Personally, I try and keep only release-ready code in the master branch.
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.
I try and use common branch naming conventions as well, such as: