SVN:用分支替换主干

160

如何将Subversion存储库的一个分支设置为新的主干?

该系统进行了重大改写:移动了文件、重写了代码、替换了旧代码、删除了部分代码,甚至有些代码被重命名。已经测试并准备好用重写后的代码取代旧的主干。

基本上可以这么做:原始主干(Trunk 5)被标记并终止,重写后的分支(Branch 6)将成为新主干(Trunk 7):

Trunk(1) --> Trunk(2) --> Trunk(5) --> ×          +--> new Trunk(7)
  \                             \                 |
  fork                         merge             ???
    \                             \               |
     +--> Branch(3) --> Branch(4) --> Branch(6) --+

所有来自旧“主干”的正在进行的更改已经合并到了“重写分支”中。

如何操作?

8个回答

123

使用svn move将旧主干的内容移动到其他地方,并将分支重命名为主干。

请注意,svn中的复制和移动类似于文件操作。您可以使用它们在存储库中移动/复制内容,这些更改也会被版本化。将“move”视为“copy + delete”。

[编辑] Nilbus刚刚通知我,如果您使用svn move将会产生合并冲突。

我仍然认为这是正确的方法。它会导致冲突,但如果您小心地合并,很有可能不会丢失任何数据。如果这让您感到困扰,请使用更好的VCS,如MercurialGit


1
如果您这样做,即使其他人在原始主干的工作副本中进行了更改并且应该合并它们,他们也会遇到冲突。这是因为文件被删除并重新添加-它们被视为具有单独历史记录的单独对象。 - Edward Anderson
@nilbus:你试过了吗?如果我没记错的话,SVN会显示文件已被删除和重新添加,但实际上它会知道文件已被移动。 - Aaron Digulla
是的。我检出了两份副本。在第一份副本中,我将目录A移动到A2和目录B移动到A。然后将A移动到B,再将A2移动回A。(重命名和重命名回来)。在第二个检出时,我更改了一个文件并尝试进行svn更新。它发生冲突,因为我更改的文件“已被删除”。在内部,它不会保存文件的重复副本,但您看到的“删除”确实在冲突时影响您。 - Edward Anderson
12
此时,我想引用Linus Torvalds的话:“Subversion一度的口号是“更好的CVS”,或者类似的东西,如果你从那样的口号开始,就没有进步的空间。 没有正确的CVS的方式。” - Aaron Digulla
3
是的。我同意。为了解决这个问题,我实际上使用 svn-git 检出了 repo,并使用 git 将分支 rebase 到主分支上。 - Edward Anderson

70

我同意使用svn移动命令来达成这个目标。

我知道其他人认为这很不寻常,但我喜欢用这种方法。当我有一个功能分支并准备将其与已经被显着修改的主干合并时,我会将其合并到一个新的分支中,通常命名为<FeatureBranchName>-Merged。然后我解决冲突并测试合并的代码。完成后,我将主干移动到“tags”文件夹,以免丢失任何内容。最后,我将我的<FeatureBranchName>-Merged移动到主干。

此外,我在执行移动操作时更喜欢避免使用工作副本,以下是命令示例:

svn move https://SVNUrl/svn/Repo/trunk https://SVNUrl/svn/Repo/tags/AnyName

svn move https://SVNUrl/svn/Repo/branches/BranchName-Merged https://SVNUrl/svn/Repo/trunk

注意:我使用1.5


2
这可能不是最佳实践,但当你有一个非常老的主干,并且每个人都像它是主干一样在分支上工作时,这肯定是最有效的。它解决了我的问题! - Alex Perrin
我需要将一个标签转换为新的主干。这基本上就是我所做的,唯一的区别是第二个操作是 svn copy {label URL} {trunk URL} - Dima Korobskiy

12

我最近刚看到这个问题,我非常满意的解决方案是在我的主干工作副本上执行

svn merge --ignore-ancestry trunk-url branch-url

这不会尝试以历史方式应用更改(保留主干中的更改)。它只是在主干和分支之间“应用差异”。这不会为未修改的文件中的用户创建任何冲突。但是,您将失去分支的历史信息,但这在执行合并时总是会发生。


1
在 SVN 1.5 版本之后,您应该能够执行保留历史记录的合并操作。 - NSherwin

9

建议您通过仓库浏览器工具进行这些更改。

通过工作副本尝试大规模的删除和移动操作是破坏工作副本的好方法。 如果您被迫使用工作副本,请在每次删除或移动操作后执行增量提交,并在每次提交后更新您的工作副本。


一个仓库的链接会很方便(只是为了方便-节省谷歌搜索的时间 :)) - Brian M. Hunt
3
抱歉,由于拼写的原因,看起来我好像在指特定的工具(已编辑)。实际上,大多数 SVN 图形用户界面工具都应该有仓库浏览器功能。顺便提一下:我使用的是 TortoiseSVN http://tortoisesvn.tigris.org/。 - Chris Nava

5
如果您想将分支变成新的主干(即)消除自创建分支以来主干中所做的所有更改,您可以执行以下操作: 1. 对主干创建分支(作为备份) 2. 对主干进行 “还原更改” 操作 (选择创建分支后的所有修订版本) 3. 将分支合并回主干。
历史记录应该保持不变。
谢谢, 罗杰

3
@Aaron Digulla和@kementeus的解决方案可行。对于Subversion 1.4仓库,复制/移动操作可能会使将来迁移到不同仓库结构或拆分仓库变得困难。
我相信1.5的改进包括更好地解决移动/复制历史记录的问题,因此对于1.5仓库可能不是问题。
对于1.4仓库,我建议使用svnadmin dumpsvndumpfilter将现有主干移动到其他位置,然后使用相同机制将分支移动到主干。将这两个dump文件加载到测试仓库中,进行验证,然后将其移动到生产环境。
当然,在开始之前备份现有仓库。
这样可以保留历史记录,而不明确记录移动/复制,并使将来的重新组织更加容易,同时保留历史记录。
编辑:按要求,从1.4 Red-Bean书籍过滤仓库历史记录中提供1.4行为的文档。
引用:
还有,复制的路径可能会给你带来一些麻烦。 Subversion支持在仓库中进行复制操作,其中通过复制某些已经存在的路径创建新路径。可能在您的仓库生命周期的某个时刻,您可能已经从一些排除的位置复制了一个文件或目录到包含的位置。为了使转储数据自给自足,svndumpfilter需要显示新路径的添加,包括由复制创建的任何文件的内容,并且不将该添加表示为源的复制不存在于您的过滤转储数据流中。但是,由于Subversion仓库转储格式仅显示每个修订版中更改的内容,因此可能无法轻松获得复制源的内容。如果您怀疑您的仓库中有这种复制,请重新考虑您的包含/排除路径集,可能还包括作为问题复制操作源的路径。
这适用于使用svndumpfilter进行迁移/重新组织的情况。有时现在做一点额外的工作可以节省以后大量的工作,通过保持未来迁移/重新组织的易用性,可以以相对较低的成本减轻风险。

为什么“svn move”不够用?你的建议看起来就像是用大锤子去杀一只苍蝇。 - Rob Williams
我曾经遇到过这个1.4的问题——如果一个SVN仓库包含目录或者分支/标签的移动(重命名),使用svndumpfilter来帮助重新组织/迁移仓库到新结构可能会失败,因为它处理历史记录不好。这已经有文档记录了,如果需要我可以找出相关参考资料。 - Ken Gentle
你能够添加该行为的引用吗? - Jacco

2
尽管上面的答案可以解决问题,但它们并不是最佳实践。最新的svn服务器和客户端会为您跟踪合并。因此,svn知道您已将哪些修订版本合并到分支中以及从哪里合并。这在将分支保持最新并将其合并回主干时非常有帮助。
无论您使用哪个版本的Subversion,都有一种最佳实践方法可以将分支中的更改返回到主干中。它在Subversion手册中有详细说明:使用Subversion进行版本控制,第4章分支和合并,保持分支同步

谢谢官方提供的信息,让我可以通过官方方法将分支合并到主干。关键词是重新整合 - Junyo

-3

这是一个在SVN中非常奇怪/不寻常的配置,即使我认为这根本不是一个“好的实践”,但无论如何,我想你可以做以下操作:

  • 检出所有源代码(svn co therootsourcetree)
  • 删除主干(svn rm trunk)
  • 将分支复制到主干(svn cp branches/thebranch /trunk)
  • 删除分支(svn rm branches/thebranch)
  • 提交更改

祝你好运!


9
这将破坏“svn move”所保留的历史记录路径。 - Rob Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接