我看看一些已知产品的Mercurial存储库,比如TortoiseHg和Python,虽然我可以看到多个人提交更改,但时间线总是看起来很干净,只有一个分支向前发展.
但是,假设您有14个人在使用相同的产品,那么在任何时候都不会很快陷入14个并行分支的分支噩梦吗?
举例来说,只有两个人,并在变更X的产品,现在开发商都开始在星期一早上独立功能的工作,所以开始都具有相同父变更.
当他们提交时,我们现在有两个分支,然后有14个人,我们很快会有10个(可能不是14个)分支需要合并回默认值.
或者......我在这里看不到什么?也许这不是一个真正的问题?
编辑:我看到对于我在这里真正要求的内容存在一些困惑,所以让我澄清一下.
我完全清楚地知道Mercurial可以轻松处理多个分支和合并,并且正如一个答案所述,即使人们处理相同的文件,他们也不会经常在相同的行上工作,即使这样,冲突也很容易处理.我也知道,如果两个人最终创建了一个合并地狱,因为他们在相同的文件中更改了很多相同的代码,这里有一些整体规划失败,因为我们已经将两个功能放在两个开发人员的完全相同的位置,而不是尝试他们一起工作,或者只是首先给两个开发人员.
所以那不是它.
我很好奇的是这些开源项目如何管理这样一个干净的历史.对我来说并不重要(正如一条评论所想的),历史是清晰的,我的意思是,我们确实并行工作,存储库能够反映出来,更好(在我看来),然而这些存储库我是我看着没有那个.他们似乎正在使用Subversion模型,在更新和合并之前你无法提交,在这种情况下,历史只是一条直线.
那他们怎么做呢?
他们是否"重新调整"这些变化,以便它们看起来跟随分支的最新提示,即使它们最初在分支历史中有所回复?移植更改集使它们看起来"已经在主分支中开始提交?
或者我看过的项目要么是如此缓慢(目前我没有在历史中看得太远)添加新事物,实际上他们一次只能为一个人工作?
或者他们是否正在向一位审核然后整合的中央维护者推动更改?它看起来并不像那样,因为我看到的许多项目在变更集上都有不同的名称.
或者......我在这里看不到什么?也许这不是一个真正的问题?
这不是一个真正的问题.在大型项目中,即使人们使用相同的功能,他们通常也不会在同一个文件上工作.当它们处理同一个文件时,它们通常不会修改相同的行.当他们修改相同的行时,应该手动完成合并(对于受影响的行).
这意味着在实践中,Mercurial本身可以自动完成80%以上的合并.
我们来举个例子:
你有:
[branch 1] [branch2]
\ /
\ /
[base]
Run Code Online (Sandbox Code Playgroud)
编辑:为清楚起见,我通过分支在这里引用未命名的分支.
如果您更改了文件,branch 1但同一文件与in branch 2相同base,则branch 1选择版本输入.如果该文件被在两个修饰的branch 1和branch 2文件合并后使用相同的算法逐行:如果在文件1线1 branch 1比file1中第1行不同的base,但branch 2与base具有1相等,在第1行线branch 1被选择(等等等).
对于在两个分支中修改的行,Mercurial会中断自动合并过程并提示用户选择要使用的行,或手动编辑行.
由于决定使用哪条线最好由修改这些线的人完成,因此一个好的做法是让实现特征的人执行合并.这意味着,如果我和你在同一个项目上工作,我会实现我的功能,然后从中央/公共存储库中获取(获取每个人使用的最新版本),然后将我的新版本与所提取的更改合并,然后发布它到公共存储库(此时,公共存储库有一个主分支,我对其进行了合并更改).然后,从服务器中提取它并对更改执行相同操作.
这意味着每个人都能够在他们的本地存储库中做任何他们想做的事情,并且公共/官方存储库有一个分支.这也意味着您需要决定人们应该合并其更改的时间范围.
我曾经在我的机器上有三个或四个存储库,这些存储库已经在不同的产品版本(存储库的不同分支)上编译,并且在我的主存储库中有一些不同的分支(一个用于重构,一个用于开发等等).每当我将一个分支带到稳定状态(比如说 - 完成重构)时,我会从服务器拉出,将该分支合并到拉出的更改中,然后将其推回服务器并让任何人知道如果他们对服务器进行了任何更改受影响的文件,应首先从服务器拉出.
我们过去常常在每个星期一早上同步已实现的功能,我们花了大约一个小时来合并所有内容,然后在服务器上进行每周构建以提供给QA(在糟糕的日子里需要两个小时左右的团队成员,然后每个人都会在他们的机器上进行一周的更改并将其用作本周的新基础.这是一个八开发团队.
在您更新的问题中,您似乎对整理历史更感兴趣.如果你有一段历史,并希望将它变成一条整齐,直线,你想要使用rebase,移植和/或mercurial队列.检查那些三个文档,你应该意识到它的完成工作流程.
编辑:因为我在等待编译,所以下面是我的意思的具体例子:
> 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"
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
做一个rebase,将变更集1变成2的孩子而不是0:
> hg rebase -s 1 -d 2
Run Code Online (Sandbox Code Playgroud)
现在让我们再次查看历史:
@ 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
Run Code Online (Sandbox Code Playgroud)
普雷斯托!单线.:)
另请注意,我没有合并.当您像这样进行rebase时,您将不得不处理合并冲突和所有内容,就像您进行合并一样.因为这几乎就是在引擎盖下发生的事情.在一个小型测试回购中进行实验.例如,尝试更改添加的文件,revision 0而不是仅添加更多文件.
我是Mercurial开发人员,所以让我解释一下我们/我是如何做到的.
在Mercurial项目中,我们接受发送到邮件列表的补丁形式的贡献.当我们应用这些时hg import,我们会对我们正在处理的分支的尖端进行隐式重组.这有助于保持历史清洁.
至于我自己的变化,我在使用它们之前使用rebase或mq线性化事物,再次保持历史整洁.这基本上是一件事
hg push # abort: creates new remote head
hg pull
hg rebase
hg push
Run Code Online (Sandbox Code Playgroud)
如果你喜欢(hg pull --rebase),你可以结合使用pull和rebase,但我总是喜欢一步一步.
顺便说一句,关于这种线性化历史的做法存在一些分歧 - 有些人认为历史应该表明事情是如何发生的,包括所有的分支和合并以及诸如此类的东西.我发现,只要你不搞乱公共变更集,那么线性化历史就没那么有用了.