私の質問に答えようとしています: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
。
- プラグ可能なマージドライバーとそれらのきめ細かい制御
rebase
svn履歴の厄介な部分を除外することができます
- 配布:これに取り組んでいるときにオフィスに来る必要はなく、電車や飛行機などで段階的に一時停止して進行する可能性があります。
- 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
おっと、これは長すぎて、手遅れになる前に停止しています..頑張ってください。