ホームページ  >  記事  >  開発ツール  >  git-merge の詳細な分析 (整理および共有)

git-merge の詳細な分析 (整理および共有)

WBOY
WBOY転載
2022-03-07 17:24:035417ブラウズ

この記事では、Git に関する関連知識を提供します。主に git-merge の関連問題について紹介します。git-merge コマンドは、指定されたコミットから現在のコミットの操作にマージするために使用されます。ブランチ、皆さんのお役に立てれば幸いです。

git-merge の詳細な分析 (整理および共有)

推奨学習: 「Git チュートリアル

1.1 概要

git-merge 内command には次の 3 つのパラメータがあります:

  • git merge [-n] [--stat] [--no-commit] [--squash] [--[no- ]編集] [-s ] [-X ] [-S[<keyid>]] [--[no-]rerere-autoupdate] [-m <msg>] [<commit>...]</msg></keyid>
  • ##git merge HEAD ...
  • ##git merge - -abort
  • 1.2 git-merge の概要

git-merge コマンドは、指定されたコミットを現在のブランチにマージするために使用されます。

注: ここで指定されたコミットは、これらの履歴コミット ノードから開始して現在の分離までを指します。

git-merge コマンドには次の 2 つの用途があります。

は、別のコード リポジトリの変更を統合するために git-pull で使用されます (例: git pull = git fetch) git merge)
  1. は、あるブランチから別のブランチにマージするために使用されます
  2. その後、
git merge topic

コマンドがマスター ブランチで実行されます。分離されたノード(つまり、トピック ブランチの A B C ノード) は、共通ノード (E ノード) からトピック ブランチの現在のコミット ノード (C ノード) までマスター ブランチ上に再表示され、マスター ブランチの先頭に位置します。そして、マスター ブランチとトピック ブランチに沿って新しいノードを作成し、マージ結果を記録します。このノードには、マージの変更を説明するユーザーの情報が含まれます。 1.3

git merge HEAD ...

Commandこのコマンドは歴史的な理由から存在しており、新しいバージョンでは使用しないでください。

git merge -m <msg> ....

1.4

git merge --abort

Command に置き換えます。このコマンドは、マージ後に競合が発生した場合にのみ使用されます。

git merge --abort

はマージ プロセスを放棄し、マージ前の状態を再構築しようとします。ただし、マージ開始時にコミットされていないファイルがある場合、git merge --abort はマージ前の状態を再現できない場合があります。 (特に、これらのコミットされていないファイルがマージ プロセス中に変更される場合)

警告:
git-merge

を実行すると、コミットされていないファイルが大量に含まれやすくなります。紛争で後退するのが困難な状況にある。したがって、git-merge を使用する場合は、コミットされていないファイルを使用することは強くお勧めできません。git-stash コマンドを使用して、これらのコミットされていないファイルを一時的に保存し、競合を解決した後に使用することをお勧めします。 git stash Popこれらのコミットされていないファイルを復元します。

2. パラメータ

このセクションでは、

git-merge

コマンド2.1

- で使用されるパラメータを紹介します。 -commit

および --no-commit

--commit

パラメーターを使用すると、マージ後にマージ結果のコミット ノードが生成されます。このパラメータは --no-commit をオーバーライドできます。 --no-commit
パラメーターを使用すると、マージの失敗を防ぐためにマージが自動的に送信されなくなり、送信前にマージ結果を確認して変更する機会がユーザーに与えられます。 2.2

--edit

および -e および --no-edit

--edit

-e は、マージと送信が成功する前に、エディターを呼び出して、自動的に生成されたマージ情報をさらに編集するために使用されます。したがって、ユーザーは合併の結果をさらに解釈し、判断することができます。 --no-edit
パラメータを使用すると、自動的にマージされた情報を受け入れることができます (これは通常は推奨されません)。

マージ時に
-m

パラメータを指定した場合 (後述)、--edit (または -e) を使用します。は依然として便利ですが、これにより、エディタで -m に含まれるコンテンツがさらに編集されます。

ノードの古いバージョンでは、ユーザーがマージ ログ情報を編集できない場合があります。

2.3
--ff

コマンド

--ff

は、早送りコマンドを指します。早送りモードを使用してマージする場合、新しいコミット ノードは作成されません。デフォルトでは、git-merge は早送りモードを採用します。 早送りモードの詳細な説明については、私の別の記事「成功した Git ブランチ モデルの「早送りについて」セクション」を参照してください。
2.4

--no-ff

コマンド早送りモードが使用できる場合でも、新しいマージ ノードを作成します。これは、

git merge

がタグをマージするときのデフォルトの動作です。 2.5

--ff-only

Command 現在の HEAD ノードが最新 (更新が最新のノードを指す) または早送りモードである場合を除きます。マージを使用できます。そうでない場合、マージは拒否され、失敗ステータスが返されます。

2.5 --log[=<n>] および --no-log

##--log[=<n>] マージして送信すると、ブランチ名に加えて、最大 n 個のマージされたコミット ノードのログ情報も含まれます。
--no-log では、この情報はリストされません。

2.6

--stat-n--no-statコマンド

--stat このパラメーターは、マージ結果の最後にファイルの差分のステータスを表示します。ファイル差異のステータスは、git 設定ファイルの merge.stat で設定することもできます。 対照的に、
-n--no-stat パラメーターでは、この情報は表示されません。

2.7

--squash および --no-squash

--squash マージが発生すると、現在のブランチと他のブランチの共通祖先ノードの後に​​他のブランチ ノードを追加し、他のブランチの最上位ノードまで圧縮します。ユーザーはレビュー後に送信して新しいノードを生成できます。

注 1: このパラメータは

--no-ff と競合します

##注 2: このパラメータを使用した後の結果は次のようになります。現在のブランチに新しいノードをコミットします。このパラメーターは、Git Flow を使用する場合など、場合によっては非常に役立ちます (Git Flow については、「成功した Git ブランチ モデル」を参照してください)。関数ブランチが機能要件を開発しているとき、開発者はローカルで多数の要件を送信することがあります。また、意味のないノードは、develop ブランチにマージする必要がある場合、この長いノード リストの変更内容を表すために新しいノードを使用するだけで済みます。 #コマンドが活躍します。さらに、機能ブランチの複数の送信が簡単ではないが意味がある場合は、
--no-ff

コマンドを使用する方が適切です。 --no-squash はまったく逆の効果があります。
2.8 -s

および
--strategy=

##-s および --strategy=

は、マージ戦略を指定するために使用されます。デフォルトでは、このパラメータが指定されていない場合、git は次の条件に従ってデフォルトのマージ戦略を使用します。

マージ ノードに 1 つの親ノードのみが含まれる場合 (早送りを使用する場合など)モード)、再帰的戦略が使用されます (以下で紹介します)。 マージされたノードに複数の親ノードが含まれる場合 (早送りなしモードを使用している場合など)、タコ戦略 (後述) が使用されます。

  1. 2.9
  2. -X <オプション>
  3. and
  4. --strategy-option=<オプション>

- ■ 、戦略の特定のパラメータを指定します (後述)。

2.10

--verify-signatures--no-verify-signatures

は、マージされたノードに GPG 署名があるかどうかを検証するために使用されます。 、マージでは GPG 署名検証のないノードを無視します。 (以下は転載記事からの引用です。原著者が見つからないため、原著者情報と原リンクを提供できません。侵害がある場合は、プライベートメッセージまたはコメントでお知らせください。 )

GPG は暗号化ソフトウェアです。GPG によって生成された公開キーを使用して、ファイルやコードをインターネット上に安全に拡散できます。

なぜ安全だと言えるのですか? Google が開発したリポジトリを例に挙げると、リポジトリでは GPG 検証が使用されています。各マイルストーン タグには GPG 暗号化検証が含まれています。マイルストーン v1.12.3 で変更を加えたい場合は、変更後にタグを削除すれば確実に可能です。同じ名前のタグを作成して、変更点を指します。ただし、変更したプロジェクトを再度複製すると、このマイルストーン タグへの変更が認識されず、検証が失敗し、変更がここで正常に実装されないことがわかります。これは GPG 検証の役割であり、プロジェクト作成者 (秘密鍵所有者) によって設定されたマイルストーンが他の人によって変更できないことを保証します。そうすれば、作成者のコードは安全に配布されたと言えます。
なぜそのような必要があるのでしょうか?プロジェクトの開発からリリース、その後の更新反復まで、多数の安定バージョンと開発バージョンが確実に存在します (不安定要素があります)。プロジェクトの開始者および所有者は、自分たちが認識する安定バージョンを定義する権利を持ち、この安定バージョンには他の開発者による変更は許可されません。 Google のリポジトリ プロジェクトを例に挙げると、プロジェクト オーナーはプロジェクト開発プロセスのポイント A を安定バージョン v1.12.3 として定義します。ユーザーは v1.12.3 バージョンをダウンロードすると、ポイント A によって生成されたプロジェクトと製品を確実に使用します。たとえ他の開発者が v1.12.3 をローカルで再指定し、修正点 B に指定できたとしても、修正版が最終的にユーザーによって使用されるときに、GPG 署名の検証が失敗するという問題が発生します。変更は有効になりません。

2.11
—概要
,

--概要なし

および--統計および --no-stat

も同様ですが、将来のバージョンでは削除される予定です。

2.12 -q および --quize

はサイレントに動作し、マージの進行状況情報は表示されません。 2.13 -v

および

--verbose

は、マージ結果の詳細情報を表示します。

2.14 --progress および --no-progress

は、マージされた進捗情報を表示するかどうかを切り替えます。どちらも指定しない場合は、標準エラー発生時に接続端末にメッセージが表示されます。すべてのマージ戦略が進行状況レポートをサポートしているわけではないことに注意してください。

2.15-S[<keyid>] および --gpg-sign[=<keyid>]

GPG 署名。

2.16-m <msg>

マージノード作成時に使用するコミット情報を設定します。
--log パラメーターが指定されている場合、コミット ノードの短いログがコミット メッセージに追加されます。

2.17--[no-]rerere-autoupdate

rerere は、記録された解像度を再利用する、記録されたソリューションを再利用することを意味します。これにより、ブロックの競合を解決する方法を Git に記憶させ、次回同じ競合が発生したときに Git が自動的に解決できるようにすることができます。

2.18--abort

現在のマージ競合処理プロセスを放棄し、マージ前の状態の再構築を試みます。

3. マージに関するその他の概念

3.1 マージ前の検出

外部ブランチをマージするときは、自分のブランチをクリーンな状態に保つ必要があります。そうしないと、マージ競合が発生します。多くの問題を引き起こします。
コミットをマージするときに無関係なファイルが記録されるのを避けるために、インデックスが指す HEAD ノードにコミットされていないファイルが登録されている場合、git-pull および git-merge コマンドは停止します。

3.2早送りマージ

通常、ブランチ マージではマージ ノードが生成されますが、いくつかの特殊なケースでは例外があります。たとえば、git pull コマンドを呼び出してリモート コードを更新する場合、ローカル ブランチにコミットがない場合は、マージ ノードを生成する必要はありません。この場合、マージ ノードは生成されず、HEAD は更新されたトップ コードを直接ポイントします。このマージ戦略は早送りマージです。

3.3 マージの詳細

上記の早送りマージ モードに加えて、マージされたブランチはマージ ノードを介して現在のブランチに結び付けられます。マージ前の現在のブランチのノードと他のブランチの最上位ノード (両方とも親ノード)。
マージされたバージョンでは、コミット ノード、HEAD ノード、インデックス ポインターを含む、関連するすべてのブランチの変更の一貫性が保たれ、ノード ツリーが更新されます。これらのノード内のファイルが重複しない限り、これらのファイルへの変更はノード ツリー内で変更および更新されます。
これらの変更を明示的にマージできない場合、次のことが起こります:

  1. HEAD ポインタが指すノードは変更されないままです。
  2. MERGE_HEADPointer Are他のブランチの上に配置されます。
  3. マージされたクリーン パスは、インデックス ファイルとノード ツリー内で同時に更新されます。
  4. 競合パスの場合、インデックス ファイルには 3 つのバージョンが記録されます。バージョン 1 には 2 つのバージョンが記録されます。祖先ノードでは、バージョン 2 は現在のブランチの先頭、つまり HEAD を記録し、バージョン 3 は MERGE_HEAD を記録します。ノード ツリー内のファイルには、マージ プログラムの結果が含まれています。たとえば、3 方向マージ アルゴリズムでは競合が発生する可能性があります。
  5. その他の変更はありません。特に、以前に行ったローカルな変更はそのまま残ります。
    マージを試みた結果、非常に複雑な競合が発生し、最初からやり直したい場合は、git merge --abort

約 3- を使用できます。ウェイ マージ アルゴリズム:
3 ウェイ マージ アルゴリズムは競合を解決する方法です。競合が発生すると、3 ウェイ マージ アルゴリズムは 3 つのノードを取得します: ローカル競合の B ノード、もう一方の C ノードブランチ、B ノードと C ノード、共通の最新の祖先ノード A。 3 方向マージ アルゴリズムは、これら 3 つのノードに基づいてマージします。具体的なプロセスは、ノード B および C をノード A と比較することです。ノード B および C のファイルがノード A のファイルと同じである場合、ノード B または C のいずれか 1 つだけがノードと比較して変更されている場合、競合は発生しません。 A の場合、ファイルは変更されたバージョンを採用します。A と比較して B と C が変更され、その変更が同じでない場合は、それらを手動でマージする必要があります。B と C が変更され、変更が同じである場合そうすると競合は発生せず、変更されたバージョンが自動的に採用されます。最終的なマージの後、D ノードが生成されます。D ノードには、B と C という 2 つの親ノードがあります。

3.4 タグのマージ

タグをマージすると、現時点で早送りモードが使用できる場合でも、Git は常にマージされたコミットを作成します。タグの情報には、投稿情報のテンプレートがあらかじめ設定されています。さらに、タグが署名されている場合、署名検出情報がコミット メッセージ テンプレートに追加されます。

3.5 競合の表現方法

マージ競合が発生すると、この部分は <<<<<<<, # で終了します。 ##========>>>>>>> を表します。 ======= より前が自ブランチの状況、 ======== より後が相手ブランチの状況です。 。

3.6 競合を解決する方法

競合を確認した後、次の 2 つの方法を選択できます:

  • 合併しないことを決定しました。現時点では、インデックスを HEAD ノードにリセットするだけです。この場合は git merge --abort が使用されます。
  • 競合を解決します。 Git は競合をマークします。競合を解決したら、git add を使用してインデックスに追加し、git commit を使用してマージ ノードを生成します。
    次のツールを使用して競合を解決できます。
  • マージ ツールを使用します。 git mergetool は、競合するマージを処理するためにビジュアル マージ ツールを呼び出します。
  • 違いを確認してください。 git diff は、3 方向の差分 (3 方向マージで使用される 3 方向比較アルゴリズム) を表示します。
  • 各ブランチの違いを確認してください。 git log --merge -p <path> は、HEAD バージョンと MERGE_HEAD バージョンの違いを表示します。
  • マージ前のバージョンを表示します。 git show :1:ファイル名共通祖先のバージョンを表示します。git show :2:ファイル名現在のブランチの HEAD バージョンを表示します。git show :3 :ファイル名相手のブランチのMERGE_HEADバージョンを表示します。

4. マージ戦略

Git では、-s パラメーターを追加することでマージ戦略を指定できます。一部のマージ戦略には独自のパラメータ オプションもあります。これらのマージ戦略のパラメータ オプションを設定するには、-X<option> を使用します。 (マージは git merge コマンドと git pull コマンドの両方で発生する可能性があるため、このマージ戦略は git pull にも適用されることを忘れないでください)。

4.1resolve

3 方向マージ アルゴリズムは、2 つのブランチ (現在のブランチとプルダウンした別のブランチなど) の最上位ノードをマージする場合にのみ使用してください。このマージ戦略は 3 方向マージ アルゴリズムに従い、2 つのブランチの HEAD ノードと共通の子ノードが 3 方向マージを実行します。
もちろん、本当に気になるのはクロスマージ(十字併合)の状況です。いわゆるクロスマージとは、複数の共通の祖先ノードが存在する状況を指します。たとえば、2 つのブランチをマージする場合、2 つの共通の祖先ノードが存在する可能性が非常に高くなります。現時点では、それに応じてマージを実行できません。 3 方向マージ アルゴリズムに変換します (共通祖先ノードが一意ではないため)。これは、解決戦略がクロスマージの問題を処理する方法です。ここでは、「Git を使用したバージョン管理」への参照を示します:

クロスクロス マージの状況では、複数のマージ ベースが考えられます。解決戦略は次のように機能します: 可能なマージ ベースの 1 つを選択し、最善の結果を期待します。これは実際には、思っているほど悪くはありません。ユーザーがコードの別の部分で作業していることが判明することがよくあります。この場合、Git は、既に存在する一部の変更を再マージしていることを検出し、重複する変更をスキップして競合を回避します。または、これらが競合を引き起こすわずかな変更である場合、少なくとも開発者にとって競合は簡単に処理できるはずです

これは簡単な翻訳です: クロスマージの場合、複数のマージ リファレンス ポイント (共通の祖先ノード) が存在します。解決戦略は次のように機能します: 可能なマージ リファレンス ポイントの 1 つを選択します。これが最もマージされた参照点であることが期待されます。良い結果が得られます。これは実際のところ、思っているほど悪くはありません。通常、ユーザーはコードのさまざまな部分を変更しますが、その場合、多くのマージ競合は実際には冗長で反復的になります。解決を使用してマージすると、生成された競合の処理が容易になり、実際にコードが失われるケースはほとんどありません。

4.2recursive

2 つのブランチをマージする場合は、3 方向マージ アルゴリズムのみを使用してください。解決とは異なり、クロス マージの場合、このマージ メソッドは再帰的に呼び出されます。共通の祖先ノードの後の 2 つのブランチの異なるノードから開始して、3 方向マージ アルゴリズムが再帰的に呼び出されてマージされます。競合が発生した場合は、その後、ファイルのマージは続行されなくなり、競合が直接スローされます。競合のない他のファイルは最上位ノードまで実行されます。さらに、このアプローチでは、ファイル名の変更を伴う操作を検出して処理できます。これは、git のマージおよびコードのプルのデフォルトのマージ アクションです。
再帰的マージ戦略には次のパラメータがあります:

4.2.1 ours

このパラメータは、競合が発生したときに現在のブランチのバージョンが自動的に使用されるように強制します。このマージ方法では問題は発生せず、git でも他のブランチのバージョンに含まれる競合内容をチェックせず、他のブランチの競合内容を破棄します。

4.2.2 彼らの

は私たちのものとはまったく逆です。
彼らのパラメータと私たちのパラメータはどちらも、バイナリ ファイルの競合をマージするのに適しています。

4.2.2 忍耐力

このパラメータを使用すると、git merge-recursive重要でない行 (関数など) の括弧の欠落を避けるために、余分な時間を費やします)。現在のブランチと他のブランチの間のバージョン ブランチの分離が非常に大きい場合は、このマージ方法を使用することをお勧めします。

4.2.3diff-algorithm=[patience|minimal|histogram|myers]

情報git merge-recursive別の比較アルゴリズムを使用する。

4.2.4 ignore-space-changeignore-all-spaceignore-space-at-eol

指定されたパラメータに従ってスペースの競合を処理します。

  • 相手のバージョンがスペースの変更のみを追加している場合、競合がマージされるときに自分のバージョンが使用されます
  • 自分のバージョンにスペースが含まれているが、相手のバージョンに多数の変更が含まれている場合変更が多い場合、競合が発生します。マージ時に相手のバージョンを使用します。
  • 通常のプロセスを使用します。

4.2.5 名前変更なし

名前変更の検出をオフにします。

4.2.6subtree[=<path>]

このオプションは、サブツリー マージ戦略の高度な形式であり、2 つのノード ツリーをマージするプロセスを推測します。 . 入居方法。違いは、指定されたパスがマージの開始時に削除されるため、サブツリーを検索するときに他のパスが照合できることです。 (サブツリー マージ戦略の詳細については、以下を参照してください)

4.3octopus

このマージ方法は 3 つ以上のブランチに使用されますが、競合により手動マージが必要な場合はマージが拒否されます。このマージ方法は、複数のブランチをバンドルするのにより適しており、複数ブランチのマージのデフォルトのマージ戦略でもあります。

4.4ours

このメソッドは任意の数のブランチをマージできますが、ノード ツリーのマージ結果は常に現在のブランチの競合部分になります。この方法は、古いバージョンを置き換える場合に非常に効率的です。このメソッドは、再帰的戦略におけるパラメータとは異なることに注意してください。

4.5subtree

サブツリーは、再帰戦略の修正バージョンです。ツリー A とツリー B をマージするとき、B が A のサブツリーである場合、B は同じノードを読み取るのではなく、まず A のツリー構造に一致するように調整します。

4.5 概要

3 方向マージ戦略 (デフォルトの再帰戦略を参照) を使用する場合、現在のブランチと他のブランチの両方でファイル (またはコード行) が変更された場合、その後、ブランチの 1 つにロールバックします。その後、このロールバックの変更が結果に反映されます。この点で混乱する人もいるかもしれません。これは、マージ プロセス中、git は 2 つのブランチのすべてのノードではなく、2 つのブランチの共通の祖先ノードと HEAD ノードのみに焦点を当てるためです。したがって、マージ アルゴリズムはロールバックされた部分を unchanged とみなし、マージされた結果が他のブランチの変更された部分になります。

5. Git の使用に関する個人的な意見

私は常に Git が非常に優れたバージョン管理ツールであると信じてきましたが、社内の多くの人が Git を使いにくいと感じています。この状況の主な理由は、以前の Subversion の使用によってもたらされた慣性が新しいテクノロジーの受け入れに影響を与えていることですが、その一方で、多くの人が GUI クライアントを通じてのみ Git を使用していることです。長い間、ほとんどの人は GUI を使用するほうが簡単に始めることができると考えてきましたが、実際にはこれには疑問があります。私の個人的な経験によると、GUI を使用すると慣性が発生し、ボタンをいくつかクリックするだけで操作が完了することが多いため、多くの人が Git コマンドを学習するのは時間とエネルギーの無駄であると考えています。しかし、実際には、Git のコマンドや概念を明確に理解していないと、これらの単純なボタンを使用すると、実際には多くの問題が発生します。多くの人は、ボタンをクリックした後に何が起こるかわかりません。また、GUI が賢すぎるため、同じボタンを使用することはできません。クリック イベントは、さまざまなパラメータを持つコマンドに対応する場合があります。結局のところ、本当に傷つくのは、何が問題なのか全く分からない可哀想なユーザーです。
全文の内容に基づいて、Git を使用する際に個人が従う規則のいくつかを要約します。いわゆる合意とは、強制的ではない自発的な行為を指します。これらの規則に従わなくても問題が発生することはありませんが、これらの規則に従うと、Git を使用する際の問題が軽減され、効率が向上する可能性があります。

  1. 送信量を増やし、プッシュ数を減らします。複数のユーザーが共同作業する場合、プッシュによって頻繁にマージ競合が発生し、効率に影響します。したがって、できる限り commit コマンドを使用し、マージの使用を減らすようにしてください。これにより、時間を大幅に節約できます。
  2. Git Flow (Git Flow) を使用します。詳細については、私の他の記事を参照してください: 成功する Git ブランチ モデル
  3. ブランチを使用し、メイン ブランチをクリーンに保ちます。ブランチでサブミットし、メイン ブランチに切り替えて更新 (git pull —rebase) し、ブランチをマージしてプッシュすることを強くお勧めします。このようなプロセスにより、クロスマージが回避されます (共通の祖先ノードが複数存在しなくなります)。実際、多くの人が git merge 操作に圧倒されていると感じる理由は、さまざまな理由によって引き起こされるクロスマージの問題です。この問題により、マージ プロセス中に一部のコードが失われます。 master ブランチをクリーンな状態に保つことで、クロスマージを回避できます。
  4. 早送りモードを無効にします。コードをプルするときは rebase パラメータを使用し (メイン ブランチをクリーンな状態に保つことが前提です)、マージ時に -no-ff パラメータを使用して早送りモードを無効にします。これにより、ノードの明瞭さが保証されるだけでなく、クロスマージが表示されます。

推奨学習: 「Git 学習チュートリアル

以上がgit-merge の詳細な分析 (整理および共有)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。