git-マージ時に特定のコミットをスキップする


200

私はGitを1年ほど使用していますが、すばらしいと思いますが、プロジェクトの2番目のバージョンを開始して、新しいブランチを開始しました。今後の最善の処理方法に少し苦労しています。

say master10(v1の場合)とmaster20(v2の場合)という2つのブランチがあります。私はブランチmaster10のv1でバグ修正を行い、master20の新しいものを開発しています。バグ修正を行うたびに、master20をチェックアウトして実行することでv2にマージしますgit merge master10ます。ここまでは順調ですね。

しかし今、私はv2には不要なv1の変更を加えましたが、他のバグ修正を引き続きマージしたいと考えています。特定のコミット(または一連のコミット)をスキップするようにGitに指示する方法はありますが、それでも今後は他のバグ修正をマージしたいと考えています。

思った git rebaseは必要なものかもしれないとが、ドキュメントを読んで、頭がほとんど爆発した。

私が欲しいのは、2つのブランチが同期していて、将来はこの同期ポイントからのコミットのみをマージすることをgitに伝える「git sync」コマンドのようなものだと思います。

助けてくれてありがとう。

回答:


289

たとえば、ブランチ「maint」から「master」へのすべてのコミットではなく、ほとんどのコミットをマージする場合は、これを行うことができます。いくつかの作業が必要です---上記のように、通常の使用例はブランチからすべてをマージすることです---しかし、統合されるべきではないリリースバージョンに変更を加えたことがあります(たぶんそのコードはマスターで既に置き換えられています)、それで、それをどのように表現しますか?ここに行く...

それで、maintに5つの変更が適用されていて、そのうちの1つ(maint〜3)がmasterにマージされないものとします。これは3つの段階で行います。実際には、その前のすべてをマージし、gitにmaint〜3がマージされていない場合でもマージ済みとしてマークし、残りをマージするように指示します。魔法は:

bash <master>$ git merge maint~4
bash <master>$ git merge -s ours maint~3
bash <master>$ git merge maint

最初のコマンドは前にすべてをマージします、面倒なmaintがマスターにコミットする。デフォルトのマージログメッセージは、「branch 'maint'(early part)」をマージしていることを説明します。

2番目のコマンドは厄介なmaint〜3コミットをマージしますが、「-s ours」オプションはgitに特別な「マージ戦略」を使用するように指示します。 )あなたは完全にマージしています。ただし、HEADとmaint〜3を親として新しいマージコミットを行うため、リビジョングラフにはmaint〜3がマージされたと表示されます。したがって、実際には、おそらく-mオプションを使用して 'git merge'を実行し、maint〜3コミットが実際には無視されていることを説明する必要があります。

最後のコマンドは、残りのmaint(maint〜2..maint)をmasterにマージするだけで、すべてが再び同期されます。


5
そのコミットのマージを延期する必要がある場合は、それをスキップして(merge -s ours)、後でcherry-pickコマンドを使用して適用するしかありません。コミットがマスターから到達可能になると、再度マージすることはできません。同じ変更を2回マージすることを回避することは、Gitの主要な目標の1つです。
araqnid

3
サブブランチの例について:サブブランチをマージすると、私の投稿の2番目のステップの後とまったく同じ状況になると思います。追加のブランチを作成しても、コミット関係に違いはありません。
araqnid

5
興味があるだけで、1つの変更を省略したい場合は、3つのマージを実行するのではなく、1つのマージを行って、その1つのチェンジセットを元に戻さないのはなぜですか。これにより、リポジトリにコミットされるチェンジセットが少なくなり、履歴がより明確になります。
マークブース

3
多くの場合、コミットに明示的に名前を付ける方が簡単です。そのため、マージするブランチのgitログを表示して、マージしてはならないコミットのハッシュとその前のハッシュを確認する必要があります
zwirbeltier

14
@MarkBooth:スキップするコミットは、マージするブランチとの大きな競合の可能性があります。競合を修正してからその変更を元に戻して競合を再度修正するのではなく、単にスキップする方が簡単です
SztupY

39

IMHO、最も論理的なことは、すべてマージしてから、git revert(commit_you_dont_want)を使用して削除することですです。

例:

git merge master
git revert 12345678

「無視する」コミットが複数ある場合、または元に戻すメッセージを編集する場合:

git merge master
git revert -n 123456
git revert -n abcdef
git commit -m "... Except commits 123456 and abcdef"

次に、あなたの履歴は次のようになります。

| ... Except 123456 and abcdef
|\ Merge branch 'master' into 'your_branch'

これらの「無視する」コミットのみが関与する競合がある場合は、以下を使用できます。

git merge master -X ours

したがって、あなたのバージョンは他のバージョンよりも持続します。エラーメッセージがなくても、これらの不要なコミットを「元に戻す」ことができます。これは、競合しなかった他の変更が含まれている可能性があり、それらを望まないためです。

「無視する」コミットだけではなく競合が発生している場合は、手動で解決する必要があります。おそらく、復帰中に再度解決する必要があります。


2
その後、元に戻されたコミットを問題のブランチにマージする場合でも、Gitはそれらを無視しますか?
AnriëtteMyburgh

@AnriëtteMyburghリバートコミットを元に戻して、後でマージすることができます。「merge -s ours」戦略では実際には簡単に実行できないものです。
リリー・チョン

おかげで、これはまさに私がマスターに必要のない機能ブランチでいくつかの古いコミットとマスターに必要な束を必要としていたものです。素敵できれい。
Vale Trujillo

17

コミットには祖先が含まれます。以前のコミットをマージせずにコミットをマージすることはできません。

もちろん、チェリーピックすることもできます。メンテナンスモードのブランチがある場合は、これで十分です。


1
おかげで、チェリーピックが仕事をします。私が望んでいたものほど良くはありませんが、それでうまくいきます。
ブラッド・ロビンソン


3

私のプロジェクトへの一種の広告@araqnidで記述されたプロセスを基本的にラップ。

次のGITフローを導入する一種のヘルパーです。

  • メンテナンスブランチからdev / masterブランチへの保留中のマージに関する毎日/毎週の通知があります
  • ブランチのメンテナはステータスをチェックし、すべてのコミットが必要かどうかを自分で決定し、それらの一部をブロックするか、開発者に自分自身をブロックするように依頼します。最後に、メンテナンスブランチはアップスチームにマージされます。

プロジェクトページからの引用:

ワークフローによっては、マスターブランチとともにメンテナンスブランチまたは顧客固有のブランチを持つことが可能です。これらのブランチは、LTSブランチとも呼ばれます。

多くの場合、ホットフィックスはバグが報告されたブランチに入り、コミットはマスターブランチにマージされます。

一般的な方法は、すべてのブランチをマスターと完全に同期させることです。つまり、マスターにすべての機能とバグ修正が含まれているかどうかを理解するために、特定のブランチとマスター間の明確な差分を確認したいとします。

ただし、特定のコミットは顧客固有であり、他のユーザーには表示されないため、望ましくない場合があります。または、あなたのマスターブランチがそれだけ問題を修正するために完全に異なるアプローチを必要とするほど分岐しました。

また、マスターからメンテナンスブランチへのチェリーピックの場合、結果のコミットはマスターでブロックされます。


0

master10ではなく、master20では必要な変更の3番目のブランチを作成します。すべての中で最も安定したブランチである「マスター」として常にmaster10を検討してください。他のすべてのブランチは常に同期しておきたいブランチです。


それはうまくいくと思いますが、私はすでにこの状態になっており、3番目のブランチはおそらく私をさらに混乱させるでしょう。:)
ブラッドロビンソン

0

このケースではなく、revertまたはcherry-pickこのケースでは、スキップする変更を、自分が行った変更よりも古いものと見なすようにgitを取得する必要があります。

そう:

  1. スキップしたいコミットの前に最後のコミットをマージします。もちろん、これは以前のすべてのコミットをマージします。 git merge ccc
  2. スキップしたいコミットをマージします。 git merge fff --no-commit
  3. マージのステージング、すべての変更のステージング解除、すべての変更の取り消し。(おそらくこれには間違いのないコマンドがありますが、UIでこの部分を実行するだけですが、方法は知っています)
  4. 空のマージを完了する git merge --continue
  5. スキップしたいコミットの後にコミットをマージします。 git merge source-branch-head

ステップ4の後、gitは既にコミットしているので(自分のバージョンを保持することを選択することにより)、そのコミットよりも新しいブランチを検討します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.