尝试回答我的问题:使用git进行svn合并似乎很有前途。
更新:这不仅有前途,而且非常成功。简而言之,
Linus是正确的。
刚完成了两个svn分支的大型合并,这些分支已经分离了1.5年; 3k文件被更改,在svn中遇到了大量冲突(我认为大约有800个)。
我发现git和git-svn非常有用:
- 自动冲突解决:起初,它给出的冲突文件要少得多(我认为大约减少了一半)
- 令人难以置信的性能
- 优秀的repo/branching model,灵活的工作流程:可以轻松地尝试各种方法,例如按块合并(按时间),始终进行完整性检查(编译等);每当遇到问题时:只需回溯。您总是可以在需要时向后退一步。
- 易用性,出色的工具:
git-log
(及其基础的git-rev-parse
选项),没有比这更强大的东西了。它也很方便:-p
可以一次性给出差异;在svn中,您会得到一个日志,然后找到该“修订版-1:修订版”的差异,或使用笨拙的用户界面。同时搜索多个分支,查找字符串何时添加/删除到存储库中
gitk
:非常有用,可以可视化分支历史记录,结合出色的搜索功能。在其他工具中都没有看到过这样的东西,特别是没有这么快。不要介意它在Tk中,它就是太棒了
git gui
:即使不是最性感的,也可以正常工作-对于新手发现东西非常有帮助
blame
:一个奇迹。是的,它会检测原始段来自哪里(复制&粘贴等)
mergetool
:比启动大型svn merge
要愉快得多,后者每次(即每5分钟)遇到冲突时都会停止,按“(p)ostpone”按钮,然后稍后手动搜索冲突文件。更喜欢在git gui
中集成此类工具(需要进行小修补程序)。
发现与svn
相比,集成外部差异工具更易配置。
- 可插拔合并驱动程序和对它们的细粒度控制
rebase
允许过滤掉较混乱的svn历史记录部分
- 分布式:在这项工作上无需到办公室,可以在火车/飞机上暂停和逐步进展。
- 使用Unison的USB驱动器使同步工作<->家变得轻而易举
- 如果没有git的疯狂压缩(具有26k个提交、大量分支和二进制文件的5年项目,主干svn检出:1.9Gb =>所有这些在完整的git存储库中:1.4Gb!),这是不可能的
因此,这确实可以使从噩梦到喜悦的差别——特别是如果你喜欢学习(在这种情况下需要付出一些努力——我想就像从自行车转向摩托车一样)。
尽管我不能强迫公司中的每个人立即切换——我真的没有打算。同样,git-svn
通过“先试水”方法拯救了我们。但看到同事们的反应,切换可能会比任何人预期的早:)
我想说——即使我们忘记合并和提交,这些东西已经很适合作为只读前端用于查询、可视化、备份等等。
注意:
"不要向Subversion存储库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分支和merge--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'
git dcommit
我知道合并跟踪在svn方面不会很好,直到我们完全切换。我等不及了。
更新: @Kevin要求更多关于合并svn分支的整个过程的细节。有很多文章和帖子,但作为一个新手,我发现其中一些令人困惑/误导/已经过时。无论如何,我现在的做法是(当然,在那次合并事件之后被困在git-svn中;就像一些新感染的同事一样)...
git svn clone -s http://svn/path/to/just-above-trunk
git svn fetch
git gui &
gitk --all
gitk my-svn-target-branch svn-branch-to-merge
git checkout -b my-merge-fun my-svn-target-branch
git config merge.conflictstyle diff3
git merge svn-branch-to-merge
git merge ma1
git merge mb1
git mergetool
git mergetool my-interesting-path
实际上,我更喜欢使用“git gui”内置的合并工具集成(右键单击冲突文件)。但这有点受限,因此请参见我的小补丁,它允许您插入一个shell脚本,您可以在其中调用任何您喜欢的合并工具(我尝试了各种工具,有时并行使用它们会引起很多麻烦...但通常我卡在kdiff3上)。
当合并步骤顺利进行(没有冲突)时,自动执行合并提交;否则,您需要解决冲突。
git commit
最后一个阶段..请注意,到目前为止我们只有本地提交,还没有与svn服务器通信。除非您使用了--squash或其他技巧,否则您现在会得到一个图形,其中您的合并提交有2个父级:您的svn-mirror分支的提示。现在这是常见的问题:svn只能接受线性历史记录..所以'git-svn'通过仅删除第二个父级(上述情况中的svn-branch-to-merge)来简化它..因此,在svn方面,真正的合并跟踪已经消失..但在这种情况下,它仍然可以正常工作。
如果您想要更安全/更清洁的方法,这就是我早期片段的用途:只需使用--squash进行最终合并。将早期片段调整为此流程:
git checkout -b dcommit_helper_for_svnbranch my-svn-target-branch
git merge --squash my-merge-fun
git commit 'nice merge summary'
git dcommit
抱歉,这篇文章已经太长了,我要停止了。祝你好运。