135

git-svn を試してみようと思った理由は、楽なマージと分岐です。次に、 man git-svn(1) が次のように言っていることに気付きました。

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

これは、svn/trunk (またはブランチ) からローカル ブランチを作成し、ハックして、svn/trunk にマージし直してから dcommit できないということですか? svn ユーザーは、1.5.x より前の svn でのマージと同じ混乱を常に経験していることを理解していますが、他に欠点はありますか? その最後の文も気になります。人々は日常的にこの種のことをしていますか?

4

6 に答える 6

175

実際、私は--no-ffgit merge のオプションでさらに良い方法を見つけました。以前使用していたこのスカッシュ テクニックはすべて不要になりました。

私の新しいワークフローは次のようになりました。

  • 私がdcommitし、SVNリポジトリを複製する唯一のブランチである「マスター」ブランチがあります(リポジトリに-s標準のSVNレイアウトがあると仮定します、、、および):trunk/branches/tags/

    git svn clone [-s] <svn-url>
    
  • 私はローカルブランチ「仕事」で働いています(ブランチ「仕事」-bを作成します)

    git checkout -b work
    
  • "work" ブランチにローカルでコミットします (-sコミット メッセージをサインオフするため)。続編では、ローカルコミットを 3 回行ったとします。

    ...
    (work)$> git commit -s -m "msg 1"
    ...
    (work)$> git commit -s -m "msg 2"
    ...
    (work)$> git commit -s -m "msg 3"
    

SVNサーバーにコミットしたい

  • [最終的に] SVN サーバーにコミットされたくない変更を隠します (コンパイルを高速化し、特定の機能に集中したいという理由だけで、メイン ファイルのコードにコメントを付けることがよくあります)。

    (work)$> git stash
    
  • SVN リポジトリを使用してマスター ブランチをリベースします (SVN サーバーから更新するため)。

    (work)$> git checkout master
    (master)$> git svn rebase
    
  • 作業ブランチに戻り、マスターでリベースします

    (master)$> git checkout work
    (work)$> git rebase master
    
  • たとえば、次のように使用して、すべてが正常であることを確認します。

    (work)$> git log --graph --oneline --decorate
    
  • --no-ffこのすばらしいオプションを使用して、「work」ブランチから「master」ブランチに 3 つのコミットすべてをマージします。

    (work)$> git checkout master
    (master)$> git merge --no-ff work
    
  • ログのステータスを確認できます。

    (master)$> git log --graph --oneline --decorate
    * 56a779b (work, master) Merge branch 'work'
    |\  
    | * af6f7ae msg 3
    | * 8750643 msg 2
    | * 08464ae msg 1
    |/  
    * 21e20fa (git-svn) last svn commit
    
  • amendここで、おそらくSVN 担当者の最後のコミットを編集 ( ) したいと思うでしょう(そうしないと、"Merge branch 'work'" というメッセージを含む単一のコミットしか表示されません)。

    (master)$> git commit --amend
    
  • 最後にSVNサーバーでコミットします

    (master)$> git svn dcommit
    
  • 仕事に戻り、最終的に隠しファイルを復元します。

    (master)$> git checkout work
    (work)$> git stash pop
    
于 2010-11-21T15:05:31.930 に答える
49

ローカル ブランチの作成は、git-svn で確実に可能です。自分でローカル ブランチを使用しているだけで、git を使用してアップストリームの svn ブランチをマージしようとしていない限り、問題はありません。

svn サーバーを追跡するために使用する「マスター」ブランチがあります。これは、私が dcommit する唯一のブランチです。何か作業をしている場合は、トピック ブランチを作成して作業を進めます。コミットしたいときは、次のようにします。

  1. すべてをトピック ブランチにコミットします
  2. git svn rebase (作業と svn の間の競合を解決します)
  3. git チェックアウト マスター
  4. git svn rebase (これにより、次のステップが早送りマージになります。以下の Aaron のコメントを参照してください)
  5. git マージ topic_branch
  6. マージの競合を解決します(この時点では何もないはずです)。
  7. git svn dcommit

また、svn にプッシュしてはならないローカルの変更 (デバッグ用) を維持する必要がある別の状況もあります。そのために、上記の master ブランチだけでなく、普段仕事をしている「work」というブランチもあります。トピック ブランチは作業から分岐します。そこで作業をコミットしたいときは、master をチェックアウトし、cherry-pick を使用して、svn にコミットしたい作業ブランチからコミットを選択します。これは、3 つのローカル変更コミットをコミットすることを避けたいためです。次に、マスター ブランチから dcommit し、すべてをリベースします。

git svn dcommit -nコミットしようとしていることを正確にコミットしようとしていることを確認するために、最初に実行する価値があります。git と違って、svn で履歴を書き換えるのは大変です!

チェリーピックを使用するよりも、ローカルの変更コミットをスキップしながら、トピック ブランチの変更をマージするためのより良い方法があるに違いないと感じているので、アイデアがあれば歓迎します。

于 2008-10-10T07:47:13.373 に答える
33

簡単な解決策:マージ後に「work」ブランチを削除します

簡単な答え:マージを含め、gitを好きなように使用できます(簡単なワークフローについては以下を参照してください)。一時的な作業ブランチを削除するには、必ず各「gitmergework」の後に「gitbranch-dwork 」を続けてください。

背景 の説明:merge / dcommitの問題は、ブランチを「git svn dcommit」すると、そのブランチのマージ履歴が「フラット化」されることです。gitは、このブランチに入ったすべてのマージ操作を忘れます。ファイルの内容だけが保持されます。しかし、このコンテンツが(部分的に)特定の他のブランチからのものであるという事実は失われます。参照:git svn dcommitがローカルブランチのマージコミットの履歴を失うのはなぜですか?

(注:git-svnがそれについてできることはあまりありません:svnは単にはるかに強力なgitマージを理解していません。したがって、svnリポジトリ内では、このマージ情報を表すことはできません。)

しかし、これが全体の問題です。'masterブランチ'にマージされた後に'work'ブランチを削除すると、gitリポジトリは100%クリーンになり、svnリポジトリとまったく同じように見えます。

私のワークフロー: もちろん、最初にリモートsvnリポジトリをローカルgitリポジトリに複製しました(これには時間がかかる場合があります)。

$> git svn clone <svn-repository-url> <local-directory>

その後、すべての作業は「ローカルディレクトリ」内で行われます。サーバーから更新を取得する必要があるときはいつでも(「svnupdate」など)、次のことを行います。

$> git checkout master
$> git svn rebase

私はすべての開発作業を、次のように作成された別のブランチ「作業」で行います。

$> git checkout -b work

もちろん、あなたはあなたの仕事のために好きなだけブランチを作成し、好きなだけそれらの間でマージしてリベースすることができます(それらが終わったらそれらを削除するだけです---以下で説明します)。私の通常の仕事では、私は非常に頻繁にコミットします:

$> git commit -am '-- finished a little piece of work'

次のステップ(git rebase -i)はオプションです--- svnにアーカイブする前に履歴をクリーンアップするだけです:他の人と共有したい安定したマイルストーンに到達したら、この「作業」の履歴を書き直しますコミットメッセージを分岐してクリーンアップします(他の開発者は、途中で行った小さな手順や間違いをすべて確認する必要はありません---結果だけです)。このために、私はします

$> git log

そして、svnリポジトリにある最後のコミットのsha-1ハッシュをコピーします(git-svn-idで示されます)。それから私は電話します

$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb

私の代わりに、最後のsvncommitのsha-1ハッシュを貼り付けるだけです。詳細については、「githelprebase」を使用してドキュメントを読むことをお勧めします。つまり、このコマンドは最初にコミットを表示するエディターを開きます----以前のコミットでスカッシュしたいすべてのコミットに対して「pick」を「squash」に変更するだけです。もちろん、最初の行は「ピック」のままにする必要があります。このようにして、多くの小さなコミットを1つ以上の意味のあるユニットに凝縮できます。エディターを保存して終了します。コミットログメッセージを書き直すように求める別のエディターが表示されます。

つまり、「コードハッキング」を終了した後、他のプログラマーにどのように提示したいか(または履歴を参照するときに数週間後にどのように作業を表示したいか)がわかるまで、「作業」ブランチをマッサージします。 。

変更をsvnリポジトリにプッシュするために、私は次のことを行います。

$> git checkout master
$> git svn rebase

これで、svnリポジトリでその間に発生したすべての変更で更新された古い「master」ブランチに戻ります(新しい変更は「work」ブランチに隠されています)。

新しい「作業」の変更と衝突する可能性のある変更がある場合は、新しい作業をプッシュする前に、ローカルでそれらを解決する必要があります(詳細は以下を参照してください)。次に、変更をsvnにプッシュできます。

$> git checkout master
$> git merge work        # (1) merge your 'work' into 'master'
$> git branch -d work    # (2) remove the work branch immediately after merging
$> git svn dcommit       # (3) push your changes to the svn repository

注1:コマンド'git branch -d work'は非常に安全です。これにより、不要になったブランチのみを削除できます(現在のブランチに既にマージされているため)。作業を「master」ブランチとマージする前にこのコマンドを誤って実行すると、エラーメッセージが表示されます。

注2:マージとdcommitの間に「gitbranch -dwork」を使用してブランチを削除してください:dcommitの後にブランチを削除しようとすると、エラーメッセージが表示されます:「gitsvn dcommit」を実行すると、gitはそれを忘れますブランチは「マスター」とマージされました。安全チェックを行わない「gitbranch-Dwork」で削除する必要があります。

ここで、「master」ブランチを誤ってハッキングしないように、すぐに新しい「work」ブランチを作成します。

$> git checkout -b work
$> git branch            # show my branches:
  master
* work

'work'をsvnの変更と統合する: 'git svn rebase'が、'work'ブランチで作業しているときに他の人がsvnリポジトリを変更したことを明らかにしたときに私が行うことは次のとおりです。

$> git checkout master
$> git svn rebase              # 'svn pull' changes
$> git checkout work           # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master            # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed

$> git checkout master         # try again to push my changes
$> git svn rebase              # hopefully no further changes to merge
$> git merge integration       # (1) merge your work with theirs
$> git branch -d work          # (2) remove branches that are merged
$> git branch -d integration   # (2) remove branches that are merged
$> git svn dcommit             # (3) push your changes to the svn repository

より強力なソリューションが存在します 。提示されたワークフローは単純です。「update/hack / dcommit」の各ラウンド内でのみgitの機能を使用しますが、長期的なプロジェクト履歴はsvnリポジトリと同じように線形のままです。これは、レガシーsvnプロジェクトの小さな最初のステップでgitマージの使用を開始したい場合は問題ありません。

gitマージに慣れたら、他のワークフローを自由に調べてください。何をしているのかがわかっている場合は、gitマージとsvnマージを組み合わせることができます( svnマージを支援するためだけにgit-svn(または同様のもの)を使用しますか?

于 2010-12-28T13:34:25.590 に答える
8

一番上のグレッグ・ヒューギルの答えは安全ではありません! 2 つの「git svn rebase」の間のトランクに新しいコミットが表示された場合、マージは早送りされません。

git-merge に「--ff-only」フラグを使用することで確実にできますが、通常はブランチで「git svn rebase」を実行せず、「git rebase master」のみを実行します (ローカルのみであると仮定します)。ブランチ)。その後、「git merge thebranch」は早送りが保証されます。

于 2010-12-16T11:49:33.077 に答える
6

git で svn ブランチをマージする安全な方法は、git merge --squash を使用することです。これにより、単一のコミットが作成され、メッセージの追加が停止されます。

svn-branch というトピック svn ブランチがあるとします。

git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch

この時点で、svn-branch からのすべての変更が 1 つのコミットに押しつぶされ、インデックスで待機しています。

git commit
于 2009-10-06T16:30:11.923 に答える
5

ローカル git ブランチを master git ブランチにリベースしてから dcommit すると、これらすべてのコミットを順番に実行したように見えるので、svn の人々は慣れているように直線的に見ることができます。したがって、トピックというローカルブランチがあると仮定すると、次のことができます

git rebase master topic

これにより、マスターブランチでコミットが再生され、dcommit の準備が整います

于 2010-03-11T09:12:22.173 に答える