使用 git-svn (或类似的)*只是*来帮助进行 svn 合并?

发布于 2024-09-03 14:36:29 字数 555 浏览 11 评论 0原文

我的项目中出现了一些复杂的颠覆合并:已经分开很长时间的大分支。 Svn 给出了太多的冲突——其中一些看起来是虚假的。


鉴于 git 因卓越的合并体验而受到称赞, 仅为了使合并更易于管理而使用 git-svn 有什么好处吗?


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

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

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

提前致谢。

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

更新:沿着这条路向下(和向上:)后请参阅我的-新手-答案。

Some complex subversion merges are coming up in my project: big branches that have been apart for a long time. Svn gives too many conflicts - and some of them seem spurious.


Given that git is praised for a superiour merge experience,
Would it be any good to use git-svn just for the benefit of making the merge more manageable?


Can you recommend other alternatives (eg. svk, hgsvn) to lessen the merge pain?

Some conflicts are easy enough to resolve (e.g java imports, whitespaces) - so I'm also wondering if there is any automated solutions for those.

A full switch to DVCS might happen in the future (some of us would love that), but not right now. (UPDATE: this isn't true any longer - the team switched fully recently and are happy about it).

Thanks in advance.

PS: there are posts that seem to be related (eg. git-svn merge 2 svn branches) but they don't fully answer this question.

Update: see my -novice- answer after going down (and up:) this road.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

妄断弥空 2024-09-10 14:36:29

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

更新:这不仅是有希望的,而且是巨大的成功。简而言之,Linus 是对的

刚刚完成了2个相隔1.5年的svn分支的大规模合并; 3k 文件被更改,在 svn 中出现大量冲突(我认为大约有 800 个)。

我找到了 git & git-svn 救星:

  • 自动冲突解决:首先,它提供了很多较少冲突的文件(我认为是一半)
  • 令人难以置信的性能
  • 出色 repo/分支模型,灵活的工作流程:轻松试验各种方法,例如逐块(及时)合并,始终进行健全性检查(编译, ETC);每当遇到麻烦时:就原路返回。当需要的时候,你总是可以后退一步。
  • 可用性,出色的工具:
    • git-log(以及底层的git-rev-parse选项),没有什么比这更强大的了。它也很方便:-p 一次性为您提供差异;在 svn 中,你会得到一个日志,然后找到“revision-1:revision”的差异,或者使用笨拙的 UI。查找何时将字符串添加到存储库中/从存储库中删除,同时搜索多个分支
    • gitk:对于可视化分支历史非常有用,并具有强大的搜索功能。在其他工具中没有见过这样的东西,尤其是没有这么快。别介意它是 Tk 的,它太棒了
    • git gui:即使不是最性感的,也能正常工作 - 对新手发现事物有很大帮助
    • 责备:奇迹。是的,它会检测原始片段的来源(复制和粘贴等)
    • mergetool:比启动大型 svn merge 更愉快的体验,然后每次(即每 5 分钟)遇到冲突时都会停止,按 '( p)ostpone',而不是稍后手动寻找冲突的文件。更喜欢集成在 git gui 中的风格(需要一个小补丁为此)。
      发现集成外部 diff 工具比 svn 中的可配置性更好。
    • 可插入合并驱动程序及其细粒度控制
    • rebase 允许过滤掉 svn 历史记录中更混乱的部分
  • 分布的混乱部分:处理此问题时无需到办公室,可以暂停并继续工作。在火车/飞机等上逐步进展。
    • 带有 Unison 的 USB 驱动器可实现同步工作<->家庭小菜一碟
    • 如果没有 git 的疯狂压缩,这是不可能的(5 年历史的项目,有 26k 次提交,大量分支和二进制文件,主干 svn 签出:1.9Gb => 所有这些都在完整的 git 存储库中:1.4Gb !)

所以,这确实可以从噩梦变成快乐 - 特别是如果你喜欢学习(在这种情况下确实需要一些努力 - 我想就像在学习自行车之后学习摩托车一样)。

尽管我不能强迫公司里的每个人都立即转换——我实际上并没有打算这么做。再次,git-svn 通过“先涉足”的方法拯救了我们。但是看到同事的反应,这种转变可能会比任何人预期的更早发生:)

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

注意:

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

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

不管怎样, dcommit 对我有用。我在我自己的 svn workbranch 上做了这件事,我只保留这个分支,所以避免了当时任何额外的冲突。然而,我决定从这个工作分支到 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 的内置合并工具集成(右键单击文件 )冲突中)。不过,这有点有限,所以请参阅上面的我的小补丁,它允许您插入一个 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 方面已经消失了..但在这种情况下就可以了。

如果您想要一种更安全/更干净的方法,这就是我之前的代码片段的用武之地:只需使用 --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

哎呀,这太长了,在太晚之前停止......祝你好运。

Trying to answer my question: using git for svn merges seems promising.

Update: it's not just promising, it's a great success. In short, Linus was right.

Just completed a huge merge of 2 svn branches that have been apart for 1.5 years; 3k files were changed, got tons of conflicts in svn (~800 I think).

I found git & git-svn a life saver:

  • auto-conflict resolution: for a start, it gave a lot less conflicted files (~half I think)
  • unbelievable performance
  • excellent repo/branching model, flexible workflows: easy experimentation with various approaches, such as chunk-by-chunk(in time) merge, always doing sanity checks(compile,etc); whenever trouble hits: just backtrack. You can always just take a step back when needed.
  • usability, great tooling:
    • git-log (and the underlying git-rev-parse options), nothing can be more powerful than this. It's handy as well: -p gives you diffs in one go; in svn you get a log, then find the diff for that "revision-1:revision", or use clumsy UIs. Find when a string was added/removed into the repo, search multiple branches simultaneously
    • gitk: hugely useful for visualising branch histories, combined with great search capabilities. Haven't seen anything like this in other tools, especially not as fast as this. Nevermind it's in Tk, it's just brilliant
    • git gui: works fine even if not the sexiest - great help for the novice to discover things
    • blame: a miracle. Yes, it detects where the original segment comes from (copy&paste etc)
    • mergetool: much more pleasant experience than kicking off the big svn merge which then stops everytime (ie. every 5 minutes) it runs into a conflict, press '(p)ostpone', than manually hunt for conflicted files later. Preferred a flavour of this integrated in git gui (needed a tiny patch for that).
      Found integrating external diff tools better configurable than in svn.
    • pluggable merge drivers and fine grained control of them
    • rebase allowed to filter out messier parts of the svn history
  • distribution: no need to come to the office when working on this, could pause & progress step-by-step on train/plane, etc..
    • a USB drive with Unison made syncing work<->home a piece of cake
    • this wouldn't have been possible without git's crazy compression (5 years old project with 26k commits, tons of branches and binary files, trunk svn checkout: 1.9Gb => all of these in the full git repo: 1.4Gb!)

So, this really can make the difference from a nightmare to joy - especially if you enjoy learning (which does take some effort in this case - I guess like learning a motorbike after a bicycle).

Even though I can't force everyone in the company to switch immediately - I really didn't intend to actually. Again, git-svn saves us by 'dipping the toe first' approach.. But seeing colleagues' reactions the switch might happen much before anyone expected:)

I'd say- even if we forget about merges & commits, this stuff is already great as a read-only frontend for queries, visualisation, backups, etc..

Caveat:

"Do not dcommit Git merge commits to
the Subversion repository. Subversion
doesn’t handle merges in the same way
as Git, and this will cause problems.
This means you should keep your Git
development history linear (i.e., no
merging from other branches, just
rebasing)."
(last paragraph of http://learn.github.com/p/git-svn.html )

Another excellent source is the Pro Git book, section 'Switching Active Branches' basically says that the merge does work, but dcommit will only store the content of the merge, but the history will be compromised (which breaks subsequent merges), so you should drop the work branch after merge.
Anyway it makes sense after all, and in practice it's easy to avoid traps here.. in svn, I found people do not usually re-merge anyway so this could only be seen as a step back if you come from git world in the first place.

Anyhow, the dcommit just worked for me. I did it onto my own svn workbranch that I kept for this only, so avoided any extra conflicts that time. However, I decided to do the final merge from this workbranch to the svn trunk in svn (after syncing up everything in git); --ignore-ancestry gave the best results there.

Update: as I found out later, the last few steps above (extra svn branch and merge--ignore-ancestry) is easily avoided by just keeping the branch you're dcomitting from linear. As Gabe says below, merge --squash just creates a simple stupid svn-friendly commit. Just when ready with huge merge(s) on the my local branch (which might take days/weeks), I would now just:

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

I know the merge tracking won't work great from the svn-side, until we switch fully. I can't wait for that.


UPDATE: @Kevin requested some more details on the whole process of merging svn branches.. There are lots articles, posts out there, but as a novice I found some of the confusing/misleading/out of date.. Anyhow, the way I do it these days (of course, stuck with git-svn after that merge affair; just as some newly infected colleagues)..

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

Actually I preferred to use 'git gui's builtin mergetool integration (right click on file in conflict). That's slightly limited though,so see my little patch above, which allows you to plugin a shell script where you can invoke whatever mergetools you prefer (I tried a variety of them sometimes in parallel as they caused a surprising amount of grief.. but normally I'm stuck with kdiff3..

When a merge step goes fine (no conflict), a merge commit is done automatically; otherwise, you resolve conflicts then

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

The last phase.. Note that so far we had only local commits, not talking to the svn server yet.
Unless you've used --squash or other tricks, you now end up with a graph where your merge commit has 2 parents: the tips of your svn-mirror branches. Now this is the usual gotcha: svn can only take linear history.. so 'git-svn' simplifies it by just dropping the second parent (svn-branch-to-merge in the above case).. so the real merge tracking is gone on the svn side..but otherwise it's fine in this case.

If you want a safer/cleaner way, this is where my earlier snippet comes in: just do the final merge with --squash. Adapted the earlier one to this flow:

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

oops, this is getting way too long, stopping before too late.. Good luck.

甜味超标? 2024-09-10 14:36:29

我自己刚刚经历过这个。 更简单的方法是通过git merge --squash 选项,它将执行合并而不记录合并提交,保持历史线性,以免混淆 git-svn。

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

I've just worked through this myself. A simpler method is to pass git merge the --squash option, which will perform the merge without recording a merge commit, keeping the history linear so as not to confuse git-svn.

My merge was also very large, and I had to set git config diff.renamelimit 0 so that git would correctly find all the renames.

百善笑为先 2024-09-10 14:36:29

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

除其他外,这些工具还解决了一些分支和合并问题。以下是概述:

  1. git-svn

    来自文档:

    <块引用>

    注意事项

    ...

    不建议在您计划提交的分支上运行 git merge 或 git pull。 Subversion 并不代表以任何合理或有用的方式进行合并;因此使用 Subversion 的用户无法看到您所做的任何合并。此外,如果您从作为 SVN 分支镜像的 git 分支合并或拉取,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 配置 $SVN_REPOS
    # 调整 $SVN_REPOS/conf/subgit.conf 以指定您的分支和标签
    # 调整$SVN_REPOS/conf/authors.txt指定git & svn 作者映射
    $ subgit 安装 $SVN_REPOS
    ...
    $ 安装成功
    

    此时,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 文档git-svn 比较页面。

  3. SmartGit

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

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

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

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

There are new tools available that fix many issues of git-svn and provide much better experience for using both Subversion and Git.

Among other things these tools fix some branching and merging problems. Here is an overview:

  1. git-svn

    From the documentation:

    CAVEATS

    ...

    Running git merge or git pull is NOT recommended on a branch you plan to dcommit from. Subversion does not represent merges in any reasonable or useful fashion; so users using Subversion cannot see any merges you've made. Furthermore, if you merge or pull from a git branch that is a mirror of an SVN branch, dcommit may commit to the wrong branch.

    There are primarily three reasons not to dcommit merge commits:

    • git-svn doesn't automatically send svn:mergeinfo property for merged branches. As result Subversion is not able to track those merges performed by git. This includes normal Git merges and cherry-picks.

    • as git-svn does not convert svn:ignore, svn:eol-style and other SVN properties automatically, merge commit does not have corresponding metadata in Git. As result, dcommit does not send these properties to SVN repository, so they get lost.

    • dcommit always sends changes to the branch referenced by a first parent of a merge commit. Sometimes changes appear where user doesn't expect them.

  2. SubGit

    SubGit is a Git-SVN bi-directional server-side mirror.

    If one has local access to Subversion repository, one can install SubGit into it:

    $ 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
    

    At this moment SubGit converts Subversion repository into Git (it works in opposite direction as well) and installs SVN and Git hooks. As result Subversion and Git repositories are synchronized: every commit and push starts hooks that convert incoming modifications immediately.

    SubGit converts svn:ignore properties into .gitignore files, svn:eol-style and svn:mime-type properties to .gitattributes, so merge commits in Git retain this metadata.

    When one pushes merge commit, SubGit converts all the new commits into Subversion revisions. It honors svn:mergeinfo property, so merge operation is properly tracked by SVN afterwards.

    Even if user pushes very complex Git history, SubGit converts all the commits keeping the merge tracking data valid. We once pushed the whole history of git.git repository at once and it was properly converted into SVN.

    SubGit is a commercial product. It is free for open-source and academic projects and also for projects with up to 10 committers.

    For more details please refer to SubGit documentation and git-svn comparison page.

  3. SmartGit

    SmartGit is a client-side alternative for git-svn.

    SmartGit also supports svn:ignore, svn:eol-style and svn:mime-type properties conversion. And it also sets svn:mergeinfo property for merge commits. It even updates necessary merge tracking data for cherry-pick commits.

    SmartGit is a commercial Git and Mercurial client. It is free for non-commercial usage.

Full disclosure: I'm one of SubGit developers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文