【问题标题】:Git-svn merge two SVN branchesGit-svn合并两个SVN分支
【发布时间】:2013-04-11 06:48:16
【问题描述】:

我已经阅读了很多关于git-svn 和合并的 SO 问题和博客。其中一些(尤其是git-svn 手册页)警告反对在我计划从dcommit 的分支附近使用合并。

其他人,如SO answer,表示只要我使用在dcommitting 之前删除的一次性 功能分支,合并就可以了。

我有两个长期存在的 SVN(和 git)分支:

  • trunk (git-svn: svn/trunk, git: master) - 稳定分支
  • branches/devel (git-svn: svn/devel, git: devel) - 我从中分叉功能分支的主要开发分支(我可以忍受将它们重新定位回devel而不是合并)。

在上图中,(1) 显示了过去的 SVN 历史,其中branches/devel 已合并到trunk

(2) 表明我已经成功dcommitted 我目前的开发回到了 SVN。

问题:我可以使用git-svn 来合并两个SVN 分支,以便历史记录显示合并点(就像SVN 本身一样)?换句话说:如果我从masterdcommit 会发生什么,如(3) 所示?

这会弄乱我的 SVN(或 git)历史吗?或者这会完全忘记devel 被合并到master 吗?

编辑:如果git 只是忘记了devel 被合并到master 中,那么dcommiting 从点(3) 和将所有提交应用为单个 patch

【问题讨论】:

    标签: git git-svn


    【解决方案1】:

    深入了解一下,我发现git支持在dcommit'ing时在SVN分支上设置svn:mergeinfo属性:

    git svn dcommit --mergeinfo "/branches/somebranch:1-3"
    

    注意!svn:mergeinfo覆盖命令行中给出的任何内容,因此请注意列出以前的合并 .

    虽然较新的 git 版本添加了 config 参数以自动设置此属性:

    config key: svn.pushmergeinfo
    

    我在使用自动合并信息时遇到了一些问题 - 由于某种原因或其他 GIT 计算错误,我无法让它工作。

    解决方案:git-merge-svn

    为了自动化该过程,我编写了一个 shell 脚本 git-merge-svn,它可用于合并两个 SVN 分支,并在 dcommit 上设置了正确的 svn:mergeinfo

    脚本处理这两种情况:

    • 分支未在 git 中合并 - 将预先执行 git merge
    • 分支已在 git 中合并(但未在 SVN 中)- 将遍历直到合并提交修订的上一个祖先。

    使用这个脚本,我能够仅在 git 端生成这些合并并保留合并信息,以便 GIT 图表很好地显示日志:

    使用示例:

    1. devel6 上进行一些提交
    2. dcommit devel6 到 SVN(需要获取提交的 SVN 修订号)
    3. 查看 testtunk6 - 是的,我知道我的名字打错了 ;-)
    4. git merge-svn devel6

    最后一条命令输出:

    % git merge-svn devel6
    About to do an SVN merge: devel6 -> testtunk6
    
    * NEW MERGE COMMIT
    |\
    | * devel6 [7b71187] (r102)
    * | testtunk6 [0682a45] (r101)
     \|
      * [273d6d6] (r100)
    
    
    STEP 1: GIT merge
    Executing:
      git merge devel6
    
    Continue? (y/n) [n]: y
    Merge made by the 'recursive' strategy.
     testfile | 1 +
     1 file changed, 1 insertion(+)
    
    STEP 2: SVN dcommit
    
    executing:
    git svn dcommit --mergeinfo
    /idp/branches/devel:9-32,35-41 /idp/branches/devel6:89 /idp/branches/devel6:94 /idp/branches/devel6:93 /idp/branches/devel6:96 /idp/branches/devel6:97 /idp/branches/devel6:99 /idp/branches/devel6:100 /idp/branches/devel6:102
    
    Continue? (y/n) [n]: y
    Committing to https://my.svn.host/svn/auth/idp/branches/testtunk6 ...
      M testfile
    Committed r103
      M testfile
    Found merge parent (svn:mergeinfo prop): 7b71187fc371d3f86658c5850009e63be88157ac
    r103 = 87759323cbadd38bac78087d57b6870a926287e7 (refs/remotes/svn/testtunk6)
    No changes between 3fb2168cfbbe605fbd810d76513443203a85a549 and refs/remotes/svn/testtunk6
    Resetting to the latest refs/remotes/svn/testtunk6
    

    【讨论】:

    • 有什么方法可以让它工作:git-merge-svn master mybranch 紧跟git-merge-svn mybranch master?第二次合并尝试 dcommit 到 mybranch,如果你再试一次,它说它已经合并(一个谎言可能是由于 git master 与一个与 mybranch 的 sha 相对应的 sha 哈希合并,尽管没有提交到 svn -虽然 git-svn-id 行在那里,因为它被 git 合并到从 mybranch 到 svn 的提交中)。
    • @ShadowCreeper - 实际上,消息可能是真的 - SVN 报告提交已经存在于 mybranch 中,它们确实存在。您的预期结果是 mybranchmaster 指向相同的 SHA1,但这对于 SVN 是不可能的 - 它的分支本质上是文件夹,两个分支必须指向不同的文件夹。因此,在 SVN 中,一切都处于最佳状态,而在 Git 中,您无法使用全部功能 - 就是这样。
    • 简而言之 - 您“推送”到 SVN 的任何 Git 分支都将作为单独的分支保留,并且不能“快进”到 Git 意义上的另一个分支,只能在常规 SVN 意义上合并。
    • @Laas 不,我的预期结果是 SVN 将 mybranchmaster 视为已合并,并且 mybranch 中的更改已提交给 master。合并不需要快进,它可以重新设置。但合并需要发生。
    • ...也许是git-merge-svn--rebase--no-ff 选项?
    【解决方案2】:

    Git 和 Svn 有不同的数据结构来保存历史记录。

    Svn 使用一个简单的树。 IE。每个提交只有一个父级,但一个提交可以有多个子级(分支)。所以,Svn 不支持合并。他们称之为“合并”的东西实际上是变更集移植,在 git 中最接近的类比是 rebase 或者可能是 cherry-pick。从 1.5 版开始,Svn 支持元信息属性svn:mergeinfo,它有助于以某种方式跟踪“合并”的内容,但它看起来主要是一种解决方法,这解释了为什么 Svn 中的分支如此难以使用。合并点是一种提交,它将所有合并的变更集和冲突解决方案压缩到一个变更集中,可能使用 svn:mergeinfo 属性进行注释。

    Git 使用Directed acyclic graph,这是描述历史合并和分支的非常自然的方式。合并点只是具有两个(或更多!)父母的另一个提交。因此,图片上的 (3) 是合并提交。所以,所有的历史看起来都很自然,它在历史图表上从当前点可以访问所有提交。

    Git-Svn 桥尽量处理 Svn 设计的缺陷,在做 dcommit 之前,它通常将所有合并的提交重新设置在当前 Svn 分支的顶部。 Asof ~2 年前,git-svn 无法提供svn:mergeinfo,所以你问的事情是不可能的。此外,当您在dcommiting 时,git 创建一个“几乎”链接到 svn 提交的“孪生”提交,因此它会重写原始提交。

    【讨论】:

    • 感谢您的解释。我最终得到了工作流程,我将rebase -i 所有一次性分支到devel,在发布点,我只是创建一个补丁并将其作为单个提交应用到master。这样master 仅包含发布提交,而开发历史仅在devel 分支中。足够好的解决方案。
    • @Laas 你的意思是使用rebase -i 将所有提交压缩为一个吗?是的......可以工作,而且很容易做到,但是它破坏了历史,但看起来它是使用 svn 可以实现的最佳效果。
    • @Laas 或者替代解决方案是选择带有-x 标志的提交范围,至少它会通过“从提交中挑选的樱桃”评论单独保持提交隐式链接它们。此评论由git log 和其他一些命令处理,这将简化一些事情。
    • 抱歉,但由于我自己找到了我的问题的确切答案,因此我不得不接受您的答案不完整。不过,您的回答仍使我朝着正确的方向前进。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2011-05-16
    • 2014-02-01
    • 1970-01-01
    • 2010-11-25
    • 2013-08-20
    • 2017-10-11
    • 1970-01-01
    • 2011-05-18
    相关资源
    最近更新 更多