译:只是路过

Chapter 8: Merge Branches

第八章:合并分支

This is part of an online book called Source Control HOWTO, a best practices guide on source control, version control, and configuration management.

这是一篇名为如何做源码控制的在线书籍的一部分,一本关于源码控制、版本控制、配置管理的最佳实践手册。

What is "merge branches"?

什么是“合并分支”?

Many users find the word "merge" to be confusing, since it seems to imply that we start out with two things and end up with only one.  I'm not going to start trying to invent new vocabulary.  Instead, let's just try to be clear about what we mean we speak about merging branches.  I define "merge branches" like this:

很多用户发现“合并”这个词比较含混,因为看来好像是在暗示从两件事情开始,然后只有一件事情结束。我不打算再去创造新的词汇。只是,我们正试图明白我们在谈及合并分支时我们的真实含义。我这样定义“合并分支”的:

To "merge branches" is to take some changes which were done to one branch and apply them to another branch.

“合并分支”就是将在一个分支完成了的变更应用到另一个分支。

Sounds easy, doesn't it?  In practice, merging branches often is easy.  But the edge cases can be really tricky.

听来很简单吧?在实践中,合并分支通常是简单的。但是有的突出的案例却真的比较复杂。

Consider an example.  Let's say that Joe has made a bunch of changes in $/branch and we want to apply those changes to $/trunk.  At some point in the past, $/branch and $/trunk were the same, but they have since diverged.  Joe has been making changes to $/branch while the rest of the team has continued making changes to $/trunk.  Now it is time to bring Joe back into the team.  We want to take all the changes Joe made to $/branch, no matter what those changes were, and we want to apply those changes to $/trunk, no matter what changes have been to $/trunk during Joe's exile.

来考虑一种情况。我们说Joe在$/branch做了一系列变更,然后我们打算将他们应用到$/trunk上。在过去的某个点,$/branch 和$/trunk是一样的,但是他们从那之后分支了。Joe开始在$/branch上进行变更,而团队其余成员在$/trunk继续进行变更。现在是时候带Joe回到团队中来了。我们希望拿到Joe在$/branch做过的所有变更,不管他改的哪里,然后我们要把它们应用到$/trunk上,不管在Joe被隔离到另一个分支后$/trunk上做了哪些变更。

The central question about merge branches is the matter of how much help the source control tool can provide.  Let's imagine that our SCM tool provided us with a slider control:

关于合并分支最重要的问题就是源码控制工具可以提供多少帮助。我们假设我们的源码控制工具为我们提供了一个滑块来控制其可以提供多少帮助:

If we drag this slider all the way to the left, the source control tool does all the work, requiring no help at all from Joe.  Speaking as a source control vendor, this is the ideal scenario that we strive for.  Most of us don't make it.  However, here at SourceGear we made the decision to build our source control product on the .NET Framework, which luckily has full support for the kind of technology needed to implement this.  The code snippet below was pasted from our implementation of the Merge Branches feature in Vault:

如果我们一下子就拖动这个滑块到最左边,源码控制工具就做所有工作,不需要Joe的任何帮助。作为源码控制工具供应商来讲,这是我们奋斗的理想境界。可是很多我们这样的供应商都没有做到。但是,最近,在SourceGear公司,我们下定决心在.NET架构上构建我们的源码控制产品,在.NET架构上,我们很幸运的得到了所有运行需要用到的技术支持。下面的代码片断就是粘贴自Vault里面执行分支合并功能的:

public void MergeBranches(Folder origin, Folder target)
{
  ArrayList changes = GetSelectedChanges(origin);

DeveloperIntention di =System.Magic.FigureOutWhatDeveloperWasTryingToDo(changes);

di.Apply(target);
}

Boy do I feel sorry for all those other source control vendors trying to implement Merge Branches without the class!  And to think that so many people believe the .NET Framework is too large.  Sheesh!

噢,我很遗憾那些其他试图做分支合并的的源码控制工具供应商没有这个!他们还在试图在没有DeveloperIntention这个类的情况下执行合并分支。然后向那么多人相信的.NET真庞大。晕!

Best Practice: Take responsibility for the merge.
最佳实践:对合并负责。
Successfully using the branching and merging features of your source control tool is first a matter of attitude on the part of the developer. No matter how much help the source control tool provides, it is not as smart as you are. You are responsible for doing the merge. Think of the tool as a tool, not as a consultant.

成功的使用你的源码控制工具的分支和合并特性是同开发人员的态度相关的。不管源码控制工具提供了多少帮助,它都不如你聪明。你要为合并负责。记住工具始终是工具,而不是顾问。

OK, I lied.  (Stop trying to add a reference to the System.Magic DLL.  It doesn't exist.)  The actual truth is that this slider can never be dragged all the way to the left.

好吧,我说谎了。(不要试图添加一个对System.Magic.DLL的引用,它不存在。)这事实是滑块根本不可能被一下就拖到左边。

If we drag the slider all the way to the right, we get a situation which is actually closer to reality.  Joe does all the work and the source control tool is no help at all.  In essence, Joe sits down with $/trunk and simply re-does the work he did in $/branch.  The context is different, so the changes he makes this time may be very different from what he did before.  But Joe is smart, and he can figure out The Right Thing to do.

如果我们把滑块一下拉到右边,我们就会遇到接近真相的情形。Joe做了所有的工作,而源码控制工具根本没有给出帮助。实质是,Joe不得不在$/trunk工作,重新将他在$/branch上已经做过的工作再重做一次。情形是不同的,所以他在之前做的变更可能同这次要做的会有很大的差异。但是Joe够聪明,他可以解决滑块右边需要做的事情。

In practice, we find ourselves somewhere between these two extremes.  The source control tool cannot do magic, but it can usually help make the merge easier.

在实际当中,我们发现我们自己常常处于两个极端之间。源码控制工具不能想像,但是通常它可以帮助我们把合并变得简单一些。

Since the developer must still take responsibility for the merge, things will go more smoothly if she understands what's really going on.  So let's talk about how merge branches works.  First I need to define a bit of terminology.

因为开发人员必须对合并负责,如果她知道什么要真正的发生,事情就会比较平稳的发展了。所以我们来讨论如何合并分支的工作。首先我需要定义一点术语。

For the remainder of this chapter I will be using the words "origin" and "target" to refer to the two branches involved in a merge branches operation.  The origin is the folder which contains the changes.  The target is the folder to which we want those changes to be applied.

在本章的剩余部分我都会用到“源”和“目标”来指明在一个合并分支操作中的两个分支。源是包含了变更的目录。目标是我们打算应用变更到里面的另一个目录。

Note that my definition of merge branches is a one-way operation.  We apply changes from the origin to the target.  In my example above, $/branch is the origin and $/trunk is the target.  That said, there is nothing which prevents me switching things around and applying changes in the opposite direction, with $/trunk as the origin and $/branch as the target, but that would simply be a separate merge branches operation.

注意,我对合并分支的定义是一个单向的操作。我们从源应用变更到目标。我上面的例子里面,$/branch就是源,$/trunk就是目标。那就是说,没有任何事情阻止我经常变换位置,甚至在相反的方向应用变更,用$/trunk做源,用$/branch做目标。但是一个单独的合并分支的操作是简单的。

Conceptually, a merge branches operation has four steps:

就概念而言,一个合并分支操作有四个步骤:

1.      Developer selects changes in the origin

2.      Source control tool applies some changes automatically to the target

3.      Developer reviews the results and resolves any conflicts

4.      Commit

1.      开发人员在源中选择目录

2.      源码控制工具自动应用一些变更到目标

3.      开发人员回顾结果并解决冲突

4.      提交

Each of these steps is described a bit more in the following sections.

在下面对每一步有更详细的描述。

1.        Selecting changes in the origin

1.在源中选择变更

When you begin a merge branches operation, you know which changes from the origin you want to be applied over in the target.  Most of the time you want to be very specific about which changes from the origin are to be merged.  This is usually evident in the conversation which preceded the merge:

当你开始一个合并分支操作,你知道你要从源应用到目标的变更。绝大多数时候你需要非常精确的知道从源里面要合并的变更。这通常显然的在合并之前的会话中:

  • "Dan asked me to merge all the bug fixes from 3.0.5 into the main trunk."
  • "Jeff said we need to merge the fix for bug 7620 from the trunk into the maintenance tree."
  • "Ian's experimental rewrite of feature X is ready to be merged into the trunk."

l          “Dan让我合并3.0.5中修复的所有缺陷到主干中”

l          “Jeff告诉我们需要从主干合并7620号缺陷的修复到维护树里面”

l          “Ian之前实验性质重写的featureX准备合并到主干”

One way or another, you need to tell your source control tool which changes are involved in the merge.  The interface for this operation can vary significantly depending on which tool you are using.  The screen shot below is the point where the Merge Branches Wizard in Vault is asking me to specify which changes should be merged.  I'm selecting everything back to the last build label:

无论如何,你要告诉你的源码控制工具在合并中应用哪些变更。这个操作的接口非常强的依赖于你使用的源码工具。下面的截图就是Vault中合并分支的指引,它要求我指定哪些变更需要合并。我在选择自上一个构建标签后的任何一个变更。

2.        Applying changes automatically to the target

2.自动应用变更到目标

After selecting the changes to be applied, it's time to try and make those changes happen in the target.  It is important here to mention that merging branches requires us to consider every kind of change, not just the common case of edited files.  We need to deal with renames, moves, deletes, additions, and whatever else the source control tool can handle.

在选择了应用变更之后,就可以试着对那些目标中的变更进行处理。必须要强调的是合并分支需要我们考虑各种类型的变更,而不是普通的编辑文件。我们需要处理重命名、移动、删除、添加或者凡是源码控制工具可以处理的。

I won't spell out every single case.  Suffice it to say that each operation should be applied to the target in the way that Makes Sense.  This won't succeed in every situation, but when it does, it is usually safe.  Examples:

我不会每个单一的案例都讲那么清楚。使它满足于说明每个操作应该被通过这种有意义的方式应用到目标就可以了。不是在任何情况下都会成功的,但是当它那样做了,它就是安全的。例如:

  • If a file was edited in the origin and a file with the same relative path exists in the target, try to make the same edit to the target file.  Use the automerge algorithm I mentioned in chapter 3.  If automerge fails, signal a conflict and ask the user what to do.
  • If a file was renamed in the origin, try doing the same rename in the target.  Here again, if the rename isn't possible, signal a conflict and ask the user what to do.  For example, the target file may have been deleted.
  • If a file was added in the origin, add it to the target.  If doing so would cause a name clash, signal a conflict and ask the user what to do.
  • What happens if an edited file in the origin has been moved in the target to a different subfolder?  Should we try to apply the edit?  I'd say yes.  If the automerge succeeds, there's a good chance it is safe.
  • 如果一个文件在源里面被编辑,然后一个有同样的文件路径的文件又存放在目标里面,就试着对目标文件进行同样的编辑。使用我在第3章提到过的自动合并的原则。如果自动合并失败了,标记冲突,告诉用户怎样做。
  • 如果源的文件被重命名了,那就试着在目标里面同样的重命名文件。再重申,如果重命名也不行,就标记冲突,告诉用户怎样做。例如,目标的文件可能被删除了。
  • 如果一个文件被添加到源,将它也添加到目标。如果这样做会导致命名冲突,标记冲突,告诉用户怎样做。
  • 如果一个已经在源里面编辑了的文件被移动到目标里面不同的子文件夹会发生什么?我们需要试着编辑吗?我会说是的。如果自动合并成功了,那就是一个说明它安全的好机会。

Bottom line, a source control tool should do all the operations which seem certain to be safe.  And even then, the user needs a chance to review everything before the merge is committed to the repository.

底线就是,一个源码控制工具应该做所有看上去可靠、安全的操作。尽管这样,用户需要一个机会在提交到库中的合并进行评估。

Let's consider a simple example from Subversion.  I created a folder called trunk, added a few files, and then branched it.  Then I made three changes to the trunk:

我们来考虑一下一个Sbuversion的简单的例子。我创建了一个叫做trunk的目录,添加了一点文件,然后对其做了分支。然后我对trunk目录做了三个变更:

  • Deleted __init__.py
  • Modified
  • Added a file called anydbm.py
  • 删除了__init__.py
  • 修改了panel.py
  • 添加了一个叫anydbm.py的文件

Then I asked Subversion to merge all changes between version 2 and 4 of my trunk into my branch:

然后我要求Subversion合并了我的主干的版本2和版本4的所有变更到我的分支:

Subversion correctly detected all three of my changes and applied them to my working copy of the branch.

Subversion正确的检测到了我这三个变更,并且将他们应用到了我的分支的工作拷贝里面。

3.        Developer review

3. 开发人员评估

Best Practice: Review the merge before you commit.
最佳实践:在你提交之前评估合并
After your source control tool has done whatever it can do, it's your turn to finish the job. Any conflicts need to be resolved. Make sure the code still builds. Run the unit tests to make sure everything still works.  Use a diff tool to review the changes.
在你的源码控制工具完成了它可以做的任何事情之后,就该到你完成这个工作了。任何冲突都需要解决。确信代码仍然被构建。运行单元测试确保代码正常工作。用一个差异比较工具来评估变更。

Merging branches should always take place in a working folder.  Your source control tool should give you a chance to do these checks before you commit the final results of a merge branches operation.

合并分支应该始终在一个工作目录中进行。你的源码控制工具应该给你一个机会去在你提交合并分支的最终结果之前检查你的工作。

The final step in a merge branches operation is a review by the developer.  The developer is ultimately responsible, and is the only one smart enough to declare that the merge is correct.  So we need to make sure that the developer is given final approval before we commit the results of our merge to the repository.

在合并分支操作中最后一步就是开发人员去评估合并分支操作。开发人员是最终的责任人,是唯一有资格宣布合并正确的人。所以我们需要确信在我们提交合并结果到库里面的时候,开发人员给出了一个正式批准。

This is the developer's opportunity to take care of anything which could not be done automatically by the source control tool in step 2.  For example, suppose the tree contains a file which is in a binary format that cannot be automatically merged, and that this file has been modified in both the origin and the target.  In this case, the developer will need to construct a version of this file which correctly incorporates both changed versions.

可以去考虑任何不会由源码控制工具在第2步里自动完成的工作,这是开发人员的幸运。例如,假设一棵树,包含了一个有二进制格式不能自动合并的文件,而且那个文件在源和目标中都被修改了。在这种情况下,开发人员需要为文件构建一个正确的合并了所有变更的版本。

4.        Commit

4.提交

The very last step of a merge branches operation is to commit the results to the repository.  Simplistically, this is a commit like any other.  Ideally, it is more.  The difference is whether or not the source control tool supports "merge history".

合并分支操作的最终的步骤就是提交结果到库里面。非常简单,这是一个类似其他提交的提交。在概念上,它要比其他的提交多点。差别就是不管源码控制工具是否支持“合并历史”。

The benefits of merge history

合并历史的益处

Merge history contains special historical information about all merge branch operations.  Each time you do use the merge branches feature, it remembers what happened.  This allows us to handle two cases with a bit more finesse:

合并历史包含了关于合并操作的所有特殊的历史信息。每次你用到合并分支特性,它就会记住发生了什么。这就允许我们用多点策略来处理两种情况:

Repeated merge. 

重复的合并。

Frequently you want to merge from the same origin to the same target multiple times.  Let's suppose you have a sub-team working in a private branch.  Every few weeks you want to merge from the branch into the trunk.  When it comes time to select the changes to be merged over, you only want to select the changes that haven't already been merged before.  Wouldn't it be nice if the source control tool would just remember this for you?

你经常都会要从同一个源合并到同一个目标很多次。那我们假设你有一个小的团队,他们工作在私有分支上。隔几周你就想将分支合并到主干上一下。当又到了选择要合并到主干的变更时,你只想选择之前没有合并过的变更。那源码工具是否好到刚好记住这些你的信息呢?

Merge history allows this and makes things more convenient.  The workaround is simply to use a label to mark the point of your last merge.

合并历史就允许这样做,并且很便利。工作区里面会简单的使用一个标签来标示你上一次合并的点。

Merge in both directions. 

从两个方向合并

A similar case happens when you have two branches and you sometimes want to merge back and forth in both directions.  For example:

一个类似的情况还会在你有两个分支,并且你有时需要从两个不同方向来回合并的时候发生。例如:

1.      Create a branch

2.      Do some work in both the branch and the trunk

3.      Merge some changes from the branch to the trunk

4.      Do some more work

5.      Merge some changes from the trunk to the branch

1.      创建一个分支

2.      在主干和分支中都做些工作

3.      从分支合并一个变更到主干

4.      做更多的工作

5.      从主干合并一些变更到分支

At step 5, when it comes time to select changes to be merged, you want the changes from step 3 to be ignored.  There is no need to merge those changes from the trunk to the branch because the branch is where those changes came from in the first place!  A source control tool with a smart implementation of merge history will know this.

在第5步,当需要选择变更进行合并的时候,你希望忽略第3步的变更。那就没有必要从主干合并变更到分支,因为分支是那些变更首先发生的地方!一个聪明的执行合并历史的源码控制工具应该知道这些的。

Not all source control tools support merge history.  A tool without merge history can still merge branches.  It simply requires the developer to be more involved, to do more thinking.

不是所有的源码控制工具支持合并历史。一个没有合并历史的工具仍然可以合并分支。它简单的要求开发人员更多的关注,进行更多的思考。

In fact, I'll have to admit that at the time of this writing, my own favorite tool falls into this category.  We're planning some major improvements to the merge branches feature for Vault 4.0, but as of version 3.x, Vault does not support merge history.  Subversion doesn't either, as of version 1.1.  Perforce is reported to have a good implementation of merge history, so we could say that its "slider" rests a bit further to the left.

事实上,我得要承认在这次编写的时候,我自己喜欢的工具开始成了这个类型。我们计划在Vault4.0里面提升合并分支的性能,但是在3.X版本,Vault不支持合并历史。Subversion在版本1.1也不支持。Perforce据报道说有一个关于合并历史的好的功能,所以我们可以说那个“滑块”离左边远了一点了。

Summary

概要

I don't want this chapter to be a step-by-step guide to using any one particular source control tool, so I'm going to keep this discussion fairly high-level.  Each tool implements the merging of branches a little differently.

我不希望这个章节是一个一步一步教你使用任何一款源码控制工具的手册,所以我将这个讨论保留在一个很高的层面。每个工具都在执行合并分支上有不同。

For some additional information, I suggest you look at Version Control with Subversion, a book from O'Reilly.  It is obviously Subversion-specific, but it contains a discussion of branching and merging which I think is pretty good.

要获取更多的信息,我建议你看看O'Reilly出版的Version Control with Subversion。那当然是Subversion的说明书,但是它包含了一个关于分支和合并的讨论,我认为写得很不错。

The one thing all these tools have in common is the need for the developer to think.  Take the time to understand exactly how the branching and merging features work in your source control tool.

所有工具共有的一个特点是需要开发人员思考。花些时间来正确理解在你的源码控制工具中分支和合并是怎么回事的。

版本控制8(译文) -(完)相关推荐

  1. numberformatexception是什么异常_译文《最常见的10种Java异常问题》

    封面:洛小汐 译者:潘潘 知彼知己,方能百战不殆. 前言 本文总结了有关Java异常的十大常见问题. 目录 检查型异常(checked) vs. 非检查型异常(Unchecked) 异常管理的最佳实践 ...

  2. java各种的不好_译文《最常见的10种Java异常问题》

    封面:洛小汐 译者:潘潘 知彼知己,方能百战不殆. 前言 本文总结了有关Java异常的十大常见问题. 目录 检查型异常(checked) vs. 非检查型异常(Unchecked) 异常管理的最佳实践 ...

  3. web标准,我们去向何方?一些想法...

    web标准,我们去向何方?一些想法... 作者:阿捷 2004-7-5 0:52:42 原文作者:Veerle 原文出处:veerle.duoh.com 原文发表时间:2004年6月14日 译者注:本 ...

  4. 大名鼎鼎的Requests库用了什么编码风格?

    原文:https://www.kennethreitz.org/essays/kenneth-reitzs-code-style 作者:Kenneth Reitz 原题:Kenneth Reitz's ...

  5. Git得基本使用方法add、commit、push、checkout以及Pull

    一.Git是什么? Git是目前世界上最先进的分布式版本控制系统. Working Directory:工作区 Index / Stage:暂存区 Repository:仓库区(或本地仓库) Remo ...

  6. Android增量代码测试覆盖率工具

    美团业务快速发展,新项目新业务不断出现,在项目开发和测试人员不足.开发同学粗心的情况下,难免会出现少测漏测的情况,如何保证新增代码有足够的测试覆盖率是我们需要思考的问题. 先看一个bug: 以上代码可 ...

  7. python 字典添加元素乱序了_Python有序字典的两个小“惊喜”

    从 Python 3.6 开始,常规的字典会记住其插入的顺序:就是说,当遍历字典时,你获得字典中元素的顺序跟它们插入时的顺序相同. 在 3.6 之前,字典是无序的:遍历顺序是随机的. 关于有序字典,这 ...

  8. 最常见的10种Java异常问题!

    封面:洛小汐 译者:潘潘 前言 本文总结了有关Java异常的十大常见问题. 目录 检查型异常(checked) vs. 非检查型异常(Unchecked) 异常管理的最佳实践箴言 为什么在try代码块 ...

  9. HTML5斯诺克桌球俱乐部【译】

    不久前,我翻译了一些技术文章,放在我的博客上,没看过的且有兴趣的朋友可以去看看:Javascript中的陷阱大集合[译].轻松学习正则表达式[译].jQuery调用Google翻译实例[译].这次这篇 ...

最新文章

  1. C# Attribute简介
  2. 大量数据转移_大量数据
  3. NBT:线虫的工程细菌共生体提高对西方玉米根虫的生防潜力
  4. 汇聚开发者星星之火,华为鸿蒙系统有希望成为国产之光?
  5. Eclipse_Eclipse下配置Maven
  6. P1991 无线通讯网
  7. lisp java_从Java调用的LISP代码
  8. SSM项目连接远程Linux服务器的mysql 启动tomcat卡在了 Initializing Spring root WebApplicationContext...
  9. 远程桌面控制VC源码剖析
  10. 微信查询对账单对账+数据读取解析入库
  11. 【Flash】关于Flash停止支持相关问题总结
  12. Python 入门学习路线
  13. 小武告诉滨滨每天可以吃一块或者两块巧克力。假设滨滨每天都吃巧克力,问滨滨共有多少种不同的吃完巧克力的方案。
  14. 停车还能360全方位影像_路虎(揽胜运动星脉极光发现)车主如何选购360全景安全辅助系统...
  15. 测试分析与测试用例设计方法
  16. gfp_mask是0代表什么?
  17. 计算机视觉入门之图像处理<六>:图像锐化处理
  18. [计算机动画]Games103-作业1-刚体动画
  19. JSP+Servlet实现留言板(简陋)
  20. matlab相机标定Options选项解析

热门文章

  1. 逻辑设计中复位的稳妥处理方法?
  2. 【 FPGA 】设置伪路径
  3. 【 MATLAB 】程序流程控制语句格式简记
  4. 矩阵的直接LU分解法
  5. 【js细节剖析】通过=操作符为对象添加新属性时,结果会受到原型链上的同名属性影响...
  6. 响应式Spring Cloud初探
  7. TScreen 类 - 获取字体列表
  8. html服务流程如何实现_朱传燕:美容院如何规范服务流程,提升专业口碑
  9. matlab画三维图
  10. VS中添加lib文件,编译出错:LINK : fatal error LNK1104: 无法打开文件:×××.lib解决办法