【问题标题】:Using git-svn (or similar) *just* to help out with an svn merge?使用 git-svn(或类似的)*just* 来帮助进行 svn 合并?
【发布时间】:2011-02-26 02:43:22
【问题描述】:

我的项目中出现了一些复杂的颠覆合并:已经分开很长时间的大分支。 Svn 提供了太多的冲突 - 其中一些似乎是虚假的。


鉴于git 因其卓越的合并体验而备受赞誉, 使用git-svn 只是为了让合并更易于管理有什么好处吗?


您能否推荐其他替代方案(例如svkhgsvn)来减轻合并的痛苦?

有些冲突很容易解决(例如 java 导入、空格)——所以我也想知道是否有针对这些的自动化解决方案。

将来可能会完全切换到 DVCS(我们中的一些人会喜欢的),但不是现在。 (更新:这不再是真的 - 团队最近完全切换并且对此感到高兴)。

提前致谢。

PS:有些帖子似乎相关(例如git-svn merge 2 svn branches),但他们并没有完全回答这个问题。

更新:在这条路下(和上)后查看我的 -novice- 答案。

【问题讨论】:

  • 为什么不只是使用 git-svn 来处理所有事情?
  • @Vi.这听起来像是一个单独的顶级问题-您可能想这样添加它:-/我的大约是:“您会在基于 SVN 的团队中引入 git-svn ,只是为了帮助大合并?”
  • just 合并后,他们可能会考虑开始just 使用它...
  • 这就是发生的事情——你可以在下面看到

标签: svn merge git-svn hgsubversion svk


【解决方案1】:

试图回答我的问题:使用 git 进行 svn 合并似乎很有希望。

更新:这不仅很有希望,而且取得了巨大的成功。简而言之,Linus was right

刚刚完成了2个已经分开1.5年的svn分支的巨大合并;修改了 3k 个文件,在 svn 中有大量冲突(我认为大约有 800 个)。

我发现 git 和 git-svn 可以救命:

  • 自动冲突解决:首先,它提供的冲突文件少了很多(我认为大约有一半)
  • 令人难以置信的性能
  • 优秀的repo/branching model,灵活的工作流程:轻松尝试各种方法,例如逐块(及时)合并,始终进行完整性检查(编译等);每当遇到麻烦时:只是回溯。您可以随时在需要时退后一步。
  • 可用性,出色的工具:
    • git-log(以及底层的git-rev-parse 选项),没有比这更强大的了。它也很方便:-p 一次性为您提供差异;在 svn 中你会得到一个日志,然后找到那个“revision-1:revision”的差异,或者使用笨拙的 UI。查找何时将字符串添加/删除到 repo 中,同时搜索多个分支
    • gitk:对于可视化分支历史非常有用,并结合了强大的搜索功能。还没有在其他工具中看到过这样的东西,尤其是没有这么快。没关系,它在 Tk 中,它很棒
    • git gui:即使不是最性感也能正常工作 - 对新手发现事物有很大帮助
    • blame:奇迹。是的,它会检测原始片段的来源(复制和粘贴等)
    • mergetool:比启动大 svn merge 更愉快的体验,然后每次(即每 5 分钟)遇到冲突时停止,按“(p)ostpone”,而不是稍后手动寻找冲突的文件。首选集成在git gui 中的这种风格(为此需要tiny patch)。 发现集成外部差异工具比在 svn 中配置更好。
    • 可插入的合并驱动程序和对它们的细粒度控制
    • rebase 允许过滤掉 svn 历史中比较混乱的部分
  • 分布:工作时不需要来办公室,可以在火车/飞机等上暂停和逐步进行。
    • 带有Unison 的 USB 驱动器让同步工作变得轻松轻松搞定
    • 如果没有 git 的疯狂压缩,这是不可能的(5 年历史的项目,有 26k 次提交,大量的分支和二进制文件,trunk svn checkout:1.9Gb => 所有这些都在完整的 git repo 中:1.4Gb! )

所以,这真的可以让噩梦变成欢乐——尤其是如果你喜欢学习(在这种情况下确实需要一些努力——我想就像在骑自行车之后学习摩托车)。

尽管我不能强迫公司里的每个人都立即切换——我真的不打算这样做。同样,git-svn 通过“先入为主”的方法拯救了我们。但看到同事的反应,这种转变可能会比任何人预期的发生得多:)

我想说 - 即使我们忘记了合并和提交,这些东西作为查询、可视化、备份等的只读前端已经很棒了。

警告:

"Do not dcommit Git 合并提交到 Subversion 存储库。颠覆 不以相同的方式处理合并 作为 Git,这会导致问题。 这意味着你应该保留你的 Git 发展历史线性(即,没有 从其他分支合并,只是 变基)。” (http://learn.github.com/p/git-svn.html最后一段)

另一个优秀的来源是Pro Git book,“切换活动分支”部分基本上说合并确实有效,但dcommit 只会存储合并的内容,但历史记录会受到影响(这会破坏后续合并),因此您应该在合并后删除工作分支。 无论如何这毕竟是有道理的,实际上很容易在这里避免陷阱.. 在 svn 中,我发现人们通常不会重新合并,所以如果你一开始来自 git 世界,这只能被视为退步地方。

无论如何,dcommit 对我有用。我在我自己的 svn 工作分支上做了这件事,我只保留了这个,所以当时避免了任何额外的冲突。但是,我决定从这个工作分支到 svn 中的 svn 主干进行最终合并(在 git 中同步所有内容之后); --ignore-ancestry 在那里给出了最好的结果。

更新:正如我后来发现的那样,只需保持您要提交的分支与线性无关,就可以轻松避免上述最后几个步骤(额外的 svn 分支和合并 --ignore-ancestry)。正如 Gabe 下面所说,merge --squash 只是创建了一个简单的愚蠢的 svn 友好提交。就在我的本地分支(可能需要数天/数周)准备好进行大规模合并时,我现在只需:

git checkout -b dcommit_helper_for_svnbranch  svnbranch
git merge --squash huge_merge_work_with_messy_nonlinear_history
git commit 'nice merge summary' # single parent, straight from the fresh svnbranch
git dcommit

我知道合并跟踪在 svn 端不会很好地工作,直到我们完全切换。我等不及了。


更新:@Kevin 要求提供有关合并 svn 分支的整个过程的更多详细信息。那里有很多文章、帖子,但作为新手,我发现了一些令人困惑/误导/过时了..无论如何,这些天我的方式(当然,在那次合并事件之后,我坚持使用 git-svn;就像一些新感染的同事一样)..

git svn clone -s http://svn/path/to/just-above-trunk  # the slowest part, but needed only once ever..you can every single branch from the svn repo since revision #1. 2) 
git svn fetch          # later, anytime: keep it up to date, talking to svn server to grab new revisions. Again: all branches - and yet it's usually a faster for me than a simple 'svn up' on the trunk:)    
# Take a look, sniff around - some optional but handy commands:
git gui   &    # I usually keep this running, press F5 to refresh
gitk --all     # graph showing all branches
gitk my-svn-target-branch svn-branch-to-merge    # look at only the branches in question
git checkout -b my-merge-fun my-svn-target-branch  # this creates a local branch based on the svn one and switches to it..before you notice :)
# Some handy config, giving more context for conflicts
git config merge.conflictstyle diff3
# The actual merge.. 
git merge  svn-branch-to-merge    # the normal case, with managable amount of conflicts
# For the monster merge, this was actually a loop for me: due to the sheer size, I split up the 2 year period into reasonable chunks, eg. ~1 months, tagged those versions ma1..ma25 and mb1..mb25 on each branch using gitk, and then repeated these for all of them
git merge ma1   # through ma25
git merge mb1   # through mb25
# When running into conflicts, just resolve them.. low tech way: keep the wanted parts, then "git add file" but you can
git mergetool   # loops through each conflicted file, open your GUI mergetool of choice..when successful, add the file automatically.
git mergetool  my-interesting-path # limit scope to that path

其实我更喜欢使用 'git gui's builtin mergetool 集成(右键单击文件冲突)。不过这有点有限,所以请看我上面的小补丁,它允许您插入一个 shell 脚本,您可以在其中调用您喜欢的任何合并工具(我有时会同时尝试各种它们,因为它们会引起令人惊讶的悲伤......但通常我被 kdiff3 困住了..

当合并步骤顺利(无冲突)时,合并提交会自动完成;否则,你解决冲突然后

git commit  # am usually doing this in the git gui as well.. again, lightning fast.

最后阶段.. 请注意,到目前为止,我们只有本地提交,还没有与 svn 服务器通信。 除非您使用过 --squash 或其他技巧,否则您现在会得到一个图表,其中您的合并提交有 2 个父项:您的 svn-mirror 分支的提示。现在这是通常的问题:svn 只能采用线性历史.. 所以 'git-svn' 通过删除第二个父级(在上述情况下为 svn-branch-to-merge)来简化它.. 所以真正的合并跟踪是在svn方面去了..但在这种情况下它很好。

如果您想要更安全/更清洁的方式,这就是我之前的 sn-p 的用武之地:只需与 --squash 进行最终合并。将较早的版本改编为此流程:

git checkout -b dcommit_helper_for_svnbranch my-svn-target-branch  # another local workbranch.. basically needed as svn branches (as any other remote branch) are read-only
git merge --squash my-merge-fun  
git commit 'nice merge summary' # single parent, straight from the fresh svn branch
git dcommit  # this will result in a 'svn commit' on the my-svn-target-branch

哎呀,这太长了,太迟了..祝你好运。

【讨论】:

  • 嗨,Inger,很高兴您可以让它工作!我是一个 git 新手,并且正在为这个用例评估 git - 合并两个具有大量文件和大量虚假 SVN 冲突的分支。您能否整理一份简短的代码清单,说明您将如何设置存储库并执行工作?例如。 git svn 克隆 myrep ; git checkout -b 分支A; git checkout -b 分支B; git 合并分支A 分支B; git commit, git svn dcommit 等等?我想确保在开始之前完全理解您的方法,因为 git svn clone 需要几天时间:-(提前致谢。
  • 更新了我的答案..希望对您有所帮助。我想这种东西会让新手有点困惑(它肯定对我有用),但过了一段时间它就会开始并有意义。只是对您的示例命令的注释,您的 2 个结帐应该是不需要的。该命令相当于“svn fetch”。在最简单的情况下,你只需要在你想合并的地方,然后'git merge otherbranch'
  • 对我的错字的后期更正:“那个命令有点相当于'svn fetch'。”应该是“.. svn switch”
  • 我刚刚(大部分)成功地做到了这一点,但我注意到我的源分支中的文件的历史记录丢失了,这些文件在我的合并过程中对它们执行了“git mv”。有没有办法避免这种情况?我想我需要在移动之前先提交,然后在 svn 工作副本上使用 tortoisesvn 来修复它。
  • Gabe 提到的git config diff.renamelimit 0 的设置可能对你有用吗?
【解决方案2】:

我自己刚刚解决了这个问题。 simpler method 是传递git merge --squash 选项,它将执行合并而不记录合并提交,保持历史线性,以免混淆git-svn。

我的合并也很大,我必须设置 git config diff.renamelimit 0 以便 git 正确找到所有重命名。

【讨论】:

  • 为此干杯。是的,我有时也使用 --squash merge 。当您想要单个组合提交而不是大量小提交时,它也很方便(作为 'rebase -i' 的替代品)。
  • --no-ff 合并选项似乎是为此而设计的:git merge --no-ff mybranch
【解决方案3】:

有一些新工具可以修复 git-svn 的许多问题,并为使用 Subversion 和 Git 提供更好的体验。

除其他外,这些工具还修复了一些分支和合并问题。这是一个概述:

  1. git-svn

    来自文档:

    注意事项

    ...

    不建议在您计划从其提交的分支上运行 git merge 或 git pull。 Subversion 不代表任何合理或有用的合并;因此使用 Subversion 的用户看不到您所做的任何合并。此外,如果你从一个 SVN 分支镜像的 git 分支合并或拉取,dcommit 可能会提交到错误的分支。

    不使用 dcommit 合并提交主要有三个原因:

    • git-svn 不会自动发送合并分支的 svn:mergeinfo 属性。结果,Subversion 无法跟踪 git 执行的那些合并。这包括正常的 Git 合并和挑选。

    • 由于 git-svn 不会自动转换 svn:ignore、svn:eol-style 和其他 SVN 属性,因此合并提交在 Git 中没有对应的元数据。结果,dcommit 不会将这些属性发送到 SVN 存储库,因此它们会丢失。

    • dcommit 始终将更改发送到合并提交的第一个父级引用的分支。有时更改会出现在用户意想不到的地方。

  2. SubGit

    SubGit 是一个 Git-SVN 双向服务器端镜像。

    如果一个人可以本地访问 Subversion 存储库,则可以将 SubGit 安装到其中:

    $ subgit configure $SVN_REPOS
    # Adjust $SVN_REPOS/conf/subgit.conf to specify your branches and tags
    # Adjust $SVN_REPOS/conf/authors.txt to specify git & svn authors mapping
    $ subgit install $SVN_REPOS
    ...
    $ INSTALLATION SUCCESSFUL
    

    此时 SubGit 将 Subversion 存储库转换为 Git(它也以相反的方向工作)并安装 SVN 和 Git 挂钩。因此,Subversion 和 Git 存储库是同步的:每次提交和推送都会启动钩子,这些钩子会立即转换传入的修改。

    SubGit 将 svn:ignore 属性转换为 .gitignore 文件,将 svn:eol-style 和 svn:mime-type 属性转换为 .gitattributes,因此 Git 中的合并提交会保留此元数据。

    当推送合并提交时,SubGit 将所有新提交转换为 Subversion 修订版。它尊重 svn:mergeinfo 属性,因此合并操作之后会被 SVN 正确跟踪。

    即使用户推送了非常复杂的 Git 历史记录,SubGit 也会转换所有提交,保持合并跟踪数据有效。我们曾经一次推送过 git.git 仓库的全部历史,并正确转换为 SVN。

    SubGit 是一个商业产品。它对开源和学术项目以及最多 10 个提交者的项目都是免费的。

    更多详情请参考SubGit documentationgit-svn对比页面。

  3. SmartGit

    SmartGit 是 git-svn 的客户端替代方案。

    SmartGit 还支持 svn:ignore、svn:eol-style 和 svn:mime-type 属性转换。它还为合并提交设置 svn:mergeinfo 属性。它甚至会更新必要的合并跟踪数据以进行樱桃选择提交。

    SmartGit 是一个商业 Git 和 Mercurial 客户端。非商业用途免费。

完全披露:我是 SubGit 开发人员之一。

【讨论】:

  • 谢谢,我以前听说过 SubGit。它看起来确实是一种强大的方法,但它似乎更针对完全转换。上面的问题更像是一个试水实验,在没有服务器访问权限的情况下进行单个 svn 合并,公司中的任何人都注意到了.. 无论如何,与此同时,我管理团队到完整的 git,以及其他一些人,并且IT 人员正在计划一个完整的迁移,双模式可能有用。所以,谢谢你的提示。顺便说一句,mergeinfo 对所有版本的 Svn 都可靠吗?
  • 我们现在正在开发 SubGit 2.0,它支持位于不同主机上的 Git 和 SVN 存储库的双向同步。基本上,可以在任何地方创建 Git 存储库,指定 SVN 存储库 URL 并为这些存储库启用 SubGit 同步。开销在 Git 端稍有延迟,而在 SVN 端则完全没有延迟。
  • 关于 svn:mergeinfo,SVN 从 1.5 版本开始支持这个属性,也就是 4 年多了。在此之前,SVN 根本不跟踪合并历史。对于 SVN 1.8,他们计划引入“对称”合并功能,以增强合并跟踪。希望这能让 SVN 在这方面与 Git/Hg/etc 相提并论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
  • 1970-01-01
  • 2011-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-16
相关资源
最近更新 更多