我查看一些已知产品的Mercurial存储库,例如TortoiseHg和Python,即使我可以看到多个人提交更改,但时间轴看起来很干净,只有一个分支向前发展
但是,假设你有14个人在同一个产品上工作,在任何时候都不会很快陷入14个并行分支的分支噩梦吗?
例如,只有两个人,以及变更集X的产品,现在两个开发人员都在星期一早上开始处理不同的功能,因此两者都以相同的父变更集开始。
当他们提交时,我们现在有两个分支,然后有14个人,我们很快会有10个(可能不是14个)分支需要合并回默认分支。
或者......我在这里看不到什么?也许这不是一个真正的问题?
编辑:我看到对于我在这里真正要求的内容存在一些困惑,所以让我澄清一下。
我完全清楚地知道Mercurial可以轻松处理多个分支和合并,并且正如一个答案所述,即使人们处理相同的文件,他们也不会经常在相同的行上工作,即便如此,冲突也是如此容易处理。我也知道,如果两个人最终创建了一个合并地狱,因为他们在同一个文件中更改了很多相同的代码,这里有一些整体规划失败,因为我们已经将两个功能放在两个开发人员的完全相同的位置,而不是尝试他们一起工作,或者只是首先给两个开发人员。
所以不是这样。
我很好奇的是这些开源项目如何管理这样一个干净的历史。对我来说并不重要(正如一条评论所想),历史是干净的,我的意思是,我们做并行工作,存储库能够反映出来,那就更好了(在我看来) ),但是我看过的这些存储库没有那个。他们似乎正在使用Subversion模型,在更新和合并之前你无法提交,在这种情况下,历史只是一条直线。
那他们是怎么做到的?
他们是否“重新调整”这些更改,以便它们看起来跟随分支的最新提示,即使它们最初在分支历史记录中有所回复?移植变更集使它们看起来“已经在主分支中开始提交?”
或者我看过的项目要么是这么缓慢(目前我没有在历史上看得太远)添加新的东西,实际上他们一次只能为一个人工作?
或者他们是否将更改推送给一位负责审核然后整合的中央维护人员?它看起来并不像那样,因为我看到的许多项目在变更集上都有不同的名称。
答案 0 :(得分:6)
或者......我在这里看不到什么? 也许这不是一个真正的问题?
这不是一个真正的问题。在大型项目中,即使人们使用相同的功能,他们通常也不会在同一个文件上工作。当它们处理同一个文件时,它们通常不会修改相同的行。当他们修改相同的行时,应该手动完成合并(对于受影响的行)。
这意味着在实践中,80%以上的合并可由Mercurial本身自动完成。
我们举一个例子:
你有:[branch 1] [branch2]
\ /
\ /
[base]
修改:为清晰起见,分支我在这里指的是未命名的分支。
如果您在branch 1
中更改了文件,但branch 2
中的相同文件与base
中的文件相同,则选择branch 1
中的版本。如果在branch 1
和branch 2
中修改了文件,则使用相同的算法逐行合并文件:如果branch 1
中的file1中的第1行与{中的file1中的第1行不同{1}}但是base
和branch 2
使第1行相等,选择了base
中的第1行(等等)。
对于在两个分支中修改的行,Mercurial会中断自动合并过程并提示用户选择要使用的行,或手动编辑行。
由于决定使用哪条线最好由修改这些线的人完成,因此一个好的做法是让实现特征的人执行合并。这意味着,如果我和你在同一个项目上工作,我会实现我的功能,然后从中央/公共存储库中获取(获取每个人使用的最新版本),然后将我的新版本与提取的更改合并,然后发布它到公共存储库(此时,公共存储库有一个主分支,我对其进行了合并更改)。然后,从服务器中提取它并对更改执行相同的操作。
这意味着每个人都能够在他们的本地存储库中做任何他们想做的事情,并且公共/官方存储库有一个分支。这也意味着你需要决定人们应该合并他们的变化的时间框架。
我曾经在我的机器上有三个或四个存储库,这些存储库已经在不同的产品版本(存储库的不同分支)上编译,并且在我的主存储库中有一些不同的分支(一个用于重构,一个用于开发等等)。每当我将一个分支带到稳定状态(比如说 - 完成重构)时,我会从服务器拉出,将该分支合并到拉出的更改中,然后将其推回服务器并让任何人知道如果他们对服务器进行了任何更改受影响的文件,应首先从服务器拉出。
我们曾经在每个星期一早上同步已实现的功能,我们花了大约一个小时来合并所有内容,然后在服务器上进行每周构建以提供给QA(在糟糕的日子里,需要两个小时的成员两个小时或者那么,每个人都会在他们的机器上拉动一周的变化并将它们用作本周的新基础。这是一个八个开发团队。
答案 1 :(得分:5)
在您更新的问题中,您似乎对整理历史的方式更感兴趣。如果您有历史记录并希望将其整合成一条整齐的直线,则需要使用rebase,transplant和/或mercurial queues。检查那些三个文档,你应该意识到它的完成工作流程。
修改:自Im waiting for a compile以来,下面是我的意思的具体示例:
> hg init
> echo test > a.txt
> hg addremove && hg commit -m "added a.txt"
> echo test > b.txt
> hg addremove && hg commit -m "added b.txt"
> hg update 0 # go back to initial revision
> echo test > c.txt
> hg addremove && hg commit -m "added c.txt"
现在,正在运行hg glog
会显示这个(分歧)历史记录,其中包含两个分支:
@ changeset: 2:c79893255a0f
| tag: tip
| parent: 0:7e1679006144
| user: mizipzor
| date: Mon Jul 05 12:20:37 2010 +0200
| summary: added c.txt
|
| o changeset: 1:74f6483b38f4
|/ user: mizipzor
| date: Mon Jul 05 12:20:07 2010 +0200
| summary: added b.txt
|
o changeset: 0:7e1679006144
user: mizipzor
date: Mon Jul 05 12:19:41 2010 +0200
summary: added a.txt
做一个rebase,将变更集1变成2的孩子而不是0:
> hg rebase -s 1 -d 2
现在让我们再次查看历史记录:
@ changeset: 2:ea0c9a705a70
| tag: tip
| user: mizipzor
| date: Mon Jul 05 12:20:07 2010 +0200
| summary: added b.txt
|
o changeset: 1:c79893255a0f
| user: mizipzor
| date: Mon Jul 05 12:20:37 2010 +0200
| summary: added c.txt
|
o changeset: 0:7e1679006144
user: mizipzor
date: Mon Jul 05 12:19:41 2010 +0200
summary: added a.txt
的Presto!单线。 :)
另请注意,我没有合并。当您像这样进行rebase时,您将不得不处理合并冲突和所有内容,就像您进行合并一样。因为这几乎就是在引擎盖下发生的事情。在一个小型测试回购中进行实验。例如,尝试更改revision 0
中添加的文件,而不是仅添加更多文件。
答案 2 :(得分:5)
我是Mercurial开发人员,所以让我解释一下我们/我是如何做到的。
在Mercurial项目中,我们接受发送到邮件列表的补丁形式的贡献。当我们应用hg import
时,我们会对我们正在处理的分支的尖端执行隐式rebase 。这有助于保持历史清洁。
至于我自己的更改,我会在推送之前使用rebase或mq来线性化事物,再次保持历史整洁。这基本上是做的事情
hg push # abort: creates new remote head
hg pull
hg rebase
hg push
如果你愿意,你可以结合使用pull和rebase(hg pull --rebase
),但我总是喜欢一步一步。
顺便说一下,对于这种线性化历史的做法存在一些分歧 - 有些人认为历史应该表明事情是如何发生的,包括所有的分支和合并以及诸如此类的东西。我发现只要你不搞乱公共变更集,那么线性化历史就没那么有用了。
答案 3 :(得分:3)
Linux内核存储在数千个存储库中,可能存在数百万个分支,这似乎不会造成问题。对于大型项目,您需要一个存储库策略(例如,独裁者 - 副手策略),但拥有多个分支是现代DVCS的主要优势而不是问题。
答案 4 :(得分:3)
是的,我们必须合并并避免主存储库上的负责人,开发人员应该在子存储库上进行合并。
因此,在将代码推送到父存储库之前,首先要提取最新更改,然后合并并尝试推送。这应该避免主仓库中不需要的头
答案 5 :(得分:2)
我不知道TortoiseHg团队如何做事,但你可以使用Mercurial的rebase extension来“分离”一个分支并将其放在尖端的顶部,创建一个分支。
但在实践中,我并不关心多个分支,只要我看不到比应有的更多的头。合并并不是什么大不了的事。