27

私のプロジェクトでは、いくつかの複雑なサブバージョンのマージが行われています。長い間離れていた大きなブランチです。Svnはあまりにも多くの競合を与えます-そしてそれらのいくつかは偽物のようです。


gitそれが優れたマージエクスペリエンスで賞賛されていることを考えると、マージをより管理しやすくするためgit-svn だけに使用するのは良いことでしょうか?


マージの痛みを軽減するために、他の選択肢(たとえばsvk、 )をお勧めできますか?hgsvn

一部の競合は簡単に解決できます(Javaインポート、空白など)。そのため、それらの自動化されたソリューションがあるかどうかも疑問に思います。

DVCSへの完全な切り替えは将来行われる可能性がありますが(私たちの中にはそれを気に入る人もいます)、現時点ではそうではありません。(更新:これはもう真実ではありません-チームは最近完全に切り替えて、それに満足しています)。

前もって感謝します。

PS:関連しているように見える投稿があります(例:git-svn merge 2 svn branchs)が、この質問に完全には答えていません。

更新:この道を下り(そして上り:)した後、私の-初心者-の答えを参照してください。

4

3 に答える 3

34

私の質問に答えようとしています:svnマージにgitを使用することは有望なようです。

更新:それは有望であるだけでなく、大成功です。要するに、Linusは正しかった。

1。5年間離れていた2つのsvnブランチの大規模なマージを完了しました。3kファイルが変更され、svnで大量の競合が発生しました(〜800だと思います)。

私はgitとgit-svnが命の恩人であることに気づきました:

  • 自動競合解決:最初に、競合するファイルがはるかに少なくなりました(〜半分だと思います)
  • 信じられないほどのパフォーマンス
  • 優れたレポ/ブランチモデル、柔軟なワークフロー:チャンクごとの(時間内の)マージ、常に健全性チェック(コンパイルなど)を行うなど、さまざまなアプローチを簡単に試すことができます。トラブルが発生したときはいつでも:ただバックトラックします。必要なときにいつでも一歩下がることができます。
  • 使いやすさ、優れたツール:
    • git-log(および基礎となるgit-rev-parseオプション)、これほど強力なものはありません。それも便利です:-p一度にdiffを提供します。svnでログを取得し、その「revision-1:revision」の差分を見つけるか、不器用なUIを使用します。文字列がリポジトリに追加/削除されたタイミングを検索し、複数のブランチを同時に検索します
    • gitk:優れた検索機能と組み合わせて、ブランチ履歴を視覚化するのに非常に役立ちます。他のツールでこのようなものを見たことがありません。特にこれほど速くはありません。それがTkにあることを気にしないでください、それはただ素晴らしいです
    • git gui:最もセクシーでなくても問題なく動作します-初心者が物事を発見するのに大いに役立ちます
    • blame: 奇跡。はい、元のセグメントがどこから来たのかを検出します(コピー&ペーストなど)
    • mergetool:後で競合するファイルを手動で探すよりも、競合が発生するたびに(つまり、5分ごとに)停止するビッグを開始するよりもはるかに快適なエクスペリエンスですsvn merge。「(p)ostpone」を押してください。統合されたこのフレーバーを好みましたgit gui(そのための小さなパッチが必要です)。外部差分ツールの統合は、よりも構成しやすいことがわかりましたsvn
    • プラグ可能なマージドライバーとそれらのきめ細かい制御
    • rebasesvn履歴の厄介な部分を除外することができます
  • 配布:これに取り組んでいるときにオフィスに来る必要はなく、電車や飛行機などで段階的に一時停止して進行する可能性があります。
    • Unisonを搭載したUSBドライブにより、同期作業が<->自宅で簡単に行えます
    • これは、gitのクレイジーな圧縮なしでは不可能でした(26kのコミット、大量のブランチとバイナリファイル、トランクsvnチェックアウト:1.9Gb =>これらすべてが完全なgitリポジトリにある5年前のプロジェクト:1.4Gb!)

ですから、これは本当に悪夢から喜びへの違いを生むことができます-特にあなたが学ぶことを楽しむなら(この場合、それはいくらかの努力を要します-私は自転車の後にバイクを学ぶのが好きだと思います)。

会社の全員にすぐに切り替えるように強制することはできませんが、実際にはそうするつもりはありませんでした。繰り返しにgit-svnなりますが、「最初につま先を浸す」アプローチによって私たちを救います。しかし、同僚の反応を見ると、誰もが予想するよりもずっと前に切り替えが発生する可能性があります:)

マージとコミットを忘れたとしても、このようなものは、クエリ、視覚化、バックアップなどの読み取り専用フロントエンドとしてすでに優れています。

警告:

「GitマージコミットをSubversionリポジトリにコミットしないでください。SubversionはGitと同じ方法でマージを処理しないため、問題が発生します。つまり、Git開発履歴を線形に保つ必要があります(つまり、他のブランチからのマージは行わないでください。リベースするだけです)。」(http://learn.github.com/p/git-svn.htmlの最後の段落)

もう1つの優れた情報源は、ProGitの本のセクション「SwitchingActiveBranches」で、基本的にマージは機能すると述べていますがdcommit、マージのコンテンツのみが保存されますが、履歴が危険にさらされるため(後続のマージが中断されます)、削除する必要がありますマージ後の作業ブランチ。とにかくそれは結局のところ理にかなっており、実際にはここでトラップを回避するのは簡単です.. svnでは、人々は通常とにかく再マージしないことがわかったので、これは最初にgitworldから来た場合にのみ後退と見なすことができます場所。

とにかく、dcommitはちょうど私のために働いた。私はこれのためだけに保持していた自分のsvnworkbranchでそれを行ったので、そのときの余分な競合を避けました。ただし、このワークブランチからsvnのsvnトランクへの最終的なマージを行うことにしました(gitですべてを同期した後)。--ignore-ancestryそこで最高の結果を出しました。

更新:後でわかったように、上記の最後のいくつかの手順(余分なsvnブランチとmerge--ignore-ancestry)は、終了するブランチを線形に保つだけで簡単に回避できます。Gabeが以下に言うように merge --squash、単純な愚かなsvn-friendlyコミットを作成するだけです。私のローカルブランチで大規模なマージの準備ができたら(数日/数週間かかる場合があります)、今は次のようになります。

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の組み込みのmergetool統合を使用することを好みました(競合するファイルを右クリックします)。ただし、これには少し制限があります。上記の小さなパッチを参照してください。シェルスクリプトをプラグインして、好きなマージツールを呼び出すことができます(驚くほどの悲しみを引き起こしたため、さまざまなものを並行して試しましたが、通常は私はkdiff3で立ち往生しています。

マージステップが正常に行われると(競合なし)、マージコミットが自動的に実行されます。それ以外の場合は、競合を解決してから

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

最後のフェーズ..これまでのところ、ローカルコミットのみがあり、svnサーバーとはまだ通信していないことに注意してください。--squashまたはその他のトリックを使用したことがない限り、マージコミットに2つの親(svn-mirrorブランチのヒント)があるグラフが作成されます。これが通常の落とし穴です。svnは線形履歴しか取得できません。したがって、'git-svn'は、2番目の親(上記の場合は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

おっと、これは長すぎて、手遅れになる前に停止しています..頑張ってください。

于 2010-06-05T19:27:01.917 に答える
3

私はこれを自分でやり遂げたところです。より簡単な方法git mergeは、オプションを渡すことです。この--squashオプションは、マージコミットを記録せずにマージを実行し、git-svnを混乱させないように履歴を線形に保ちます。

私のマージも非常に大きく、git config diff.renamelimit 0gitがすべての名前変更を正しく検出するように設定する必要がありました。

于 2010-08-27T15:27:52.617 に答える
3

git-svnの多くの問題を修正し、SubversionとGitの両方を使用するためのはるかに優れたエクスペリエンスを提供する新しいツールが利用可能です。

特に、これらのツールはいくつかの分岐とマージの問題を修正します。概要は次のとおりです。

  1. git-svn

    ドキュメントから:

    警告

    ..。

    dcommitを計画しているブランチでgitmergeまたはgitpullを実行することはお勧めしません。Subversionは、合理的または有用な方法でのマージを表すものではありません。そのため、Subversionを使用しているユーザーは、あなたが行ったマージを見ることができません。さらに、SVNブランチのミラーであるgitブランチからマージまたはプルすると、dcommitが間違ったブランチにコミットする可能性があります。

    マージコミットをdcommitしない主な理由は3つあります。

    • git-svnは、マージされたブランチのsvn:mergeinfoプロパティを自動的に送信しません。その結果、Subversionはgitによって実行されたマージを追跡できません。これには、通常のGitマージとチェリーピックが含まれます。

    • git-svnはsvn:ignore、svn:eol-style、およびその他のSVNプロパティを自動的に変換しないため、mergecommitには対応するメタデータが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のドキュメントgit-svnの比較ページを参照してください。

  3. SmartGit

    SmartGitは、git-svnのクライアント側の代替手段です。

    SmartGitは、svn:ignore、svn:eol-style、およびsvn:mime-typeプロパティの変換もサポートしています。また、マージコミット用にsvn:mergeinfoプロパティを設定します。チェリーピックコミットに必要なマージ追跡データも更新します。

    SmartGitは、商用のGitおよびMercurialクライアントです。非営利目的の使用は無料です。

完全開示:私はSubGit開発者の1人です。

于 2012-10-06T02:04:56.207 に答える