Gitでマージの衝突を解決するにはどうすればよいですか?
試してみてください:git mergetool`
GUIを開くと、各コンフリクトを順を追って説明し、マージする方法を選択することができます。 その後、手作業で少し編集する必要がある場合もありますが、通常はそれだけで十分です。 手作業で全部やるよりずっといいのは確かです。
JoshGloverのコメント通りです:
GUIをインストールしない限り、コマンドでGUIが開くとは限りません。私の場合、git mergetool
を実行すると、vimdiff
が使用される結果となりました。代わりに以下のツールのいずれかをインストールして使用することができます:meld、
opendiff、
kdiff3、
tkdiff、
xxdiff、
tortoisemerge、
gvimdiff、
diffuse、
ecmerge、
p4merge、
araxis,
vimdiff,
emerge`.
以下は、vimdiff
を使用してマージの競合を解決するサンプル手順です。このリンク]1に基づいています。
ステップ1:ターミナルで以下のコマンドを実行します。
git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false
これにより、vimdiffがデフォルトのマージツールに設定されます。
ステップ2:ターミナルで以下のコマンドを実行します。
git mergetool
ステップ3に進みます:以下のフォーマットでvimdiffが表示されます。
╔═══════╦══════╦════════╗
║ ║ ║ ║
║ LOCAL ║ BASE ║ REMOTE ║
║ ║ ║ ║
╠═══════╩══════╩════════╣
║ ║
║ MERGED ║
║ ║
╚═══════════════════════╝
この4つのビューは
LOCAL - これは現在のブランチからのファイルです。
BASE - 共通の祖先、両者の変更前のファイルの様子。
REMOTE - ブランチにマージするファイルです。
MERGED - マージした結果、レポに保存されるのはこれです。
これらのビューは ctrl+w を使って移動することができます。MERGEDビューには、ctrl+wに続けてjで直接アクセス可能です。
vimdiffナビゲーションの詳細はこちらとこちらを参照してください。
Step 4.MERGEDビューを次のように編集することができます。
REMOTEから変更点を取得したい場合
:diffg RE
BASEから変更点を取得したい場合
:diffg BA
LOCALから変更点を取得したい場合
:diffg LO
Step 5.保存、終了、コミット、クリーンアップ
:wqa
保存してviから終了する。
git commit -m "message"`.
git clean
diffツールで作成された余分なファイル(例: *.orig)を削除します。
上から、おそらく使用例を示します。
あなたはいくつかの変更を引っ張るつもりですが、おっと、あなたは最新ではありません:
git fetch origin
git pull origin master
From ssh://[email protected]:22/projectname
* branch master -> FETCH_HEAD
Updating a030c3a..ee25213
error: Entry 'filename.c' not uptodate. Cannot merge.
だからあなたは最新の状態になってもう一度試みますが、矛盾があります:
git add filename.c
git commit -m "made some wild and crazy changes"
git pull origin master
From ssh://[email protected]:22/projectname
* branch master -> FETCH_HEAD
Auto-merging filename.c
CONFLICT (content): Merge conflict in filename.c
Automatic merge failed; fix conflicts and then commit the result.
したがって、変更を確認することにしました。
git mergetool
ああ、ああ、私の上流はいくつかのことを変えましたが、私の変更を使用するだけです。.。番号。.。彼らは変わります。..
git checkout --ours filename.c
git checkout --theirs filename.c
git add filename.c
git commit -m "using theirs"
そして最後にやってみます。
git pull origin master
From ssh://[email protected]:22/projectname
* branch master -> FETCH_HEAD
Already up-to-date.
たーだ。!
マージツールが競合や解決策を理解するのに役立つのはめったにありません。 私は通常、テキストエディターで競合マーカーを見て、補足としてgit logを使用する方が成功しています。
ここにいくつかのヒントがあります:
私が見つけた最高のものは、「diff3」マージ競合スタイルを使用することです。
git config merge.conflictstyle diff3
。
これにより、次のような競合マーカーが生成されます。
<<<<<<<
Changes made on the branch that is being merged into. In most cases,
this is the branch that I have currently checked out (i.e. HEAD).
|||||||
The common ancestor version.
=======
Changes made on the branch that is being merged in. This is often a
feature/topic branch.
>>>>>>>
中央のセクションは、共通の祖先がどのように見えたかです。 これは、上下のバージョンと比較して、各ブランチで何が変更されたかをよりよく理解できるため、各変更の目的がどのようなものであったかについてより良いアイデアが得られるため、便利です。
競合がほんの数行である場合、これは通常、競合を非常に明白にします。 (競合を修正する方法を知ることは非常に異なります。他の人が何に取り組んでいるかを認識する必要があります。 混乱している場合は、その人を部屋に電話して、あなたが見ているものを見ることができるようにするのがおそらく最善です。)。
競合が長い場合は、3つのセクションをそれぞれ切り取って、「マイネ」、「コモン」、「彼ら」などの3つの別々のファイルに貼り付けます。
次に、次のコマンドを実行して、競合を引き起こした2つの差分を確認できます。
diff common mine
diff common theirs
これは、マージツールの使用と同じではありません。マージツールには、競合しないすべての差分ハンクも含まれるためです。 気が散るようです。
誰かがすでにこれについて言及しましたが、各差分ハンクの背後にある意図を理解することは、一般に、紛争がどこから来たのか、どのように対処するかを理解するのに非常に役立ちます。
git log --merge -p <name of file>
これは、共通の祖先とマージしている2つのヘッドの間でそのファイルに触れたすべてのコミットを示しています。 (したがって、マージする前に両方のブランチにすでに存在するコミットは含まれません。)これは、現在の紛争の要因ではないdiff hunksを無視するのに役立ちます。
自動化されたツールで変更を確認します。
自動テストがある場合は、それらを実行します。 lintを使用している場合は、それを実行します。 それがビルド可能なプロジェクトである場合、コミットする前にビルドするなどします。 すべての場合において、変更が何も壊さないことを確認するために、少しテストを行う必要があります。 (ヘック、競合のないマージでも、作業コードを壊す可能性があります。)。
事前に計画します。同僚とコミュニケーションをとります。
詳細はまだ新鮮ですが、事前に計画し、他の人が取り組んでいることに気づくことは、マージの競合を防止したり、早期に解決したりするのに役立ちます。
たとえば、あなたと他の人が両方とも同じファイルのセットに影響を与える異なるリファクタリングに取り組んでいることを知っている場合は、事前に互いに話し合い、それぞれがどのような種類の変更を行っているかについてより良い感覚を得る必要があります作る。 計画された変更を並行してではなく連続して行うと、かなりの時間と労力を節約できる可能性があります。
大規模なコードスワスを横切る主要なリファクタリングについては、連続して作業することを強く検討する必要があります。1人が完全なリファクタリングを実行している間、誰もがコードのその領域での作業を停止します。
(時間のプレッシャーのために)連続して作業できない場合は、予想されるマージの競合について通信することで、詳細がまだ新鮮な状態で問題をより早く解決できます。 たとえば、同僚が1週間の期間にわたって破壊的な一連のコミットを実行している場合、その週の間に、その同僚のブランチに1日1〜2回マージ/リベースを選択できます。 そうすれば、マージ/リベースの競合が見つかった場合、数週間待ってすべてを1つの大きな塊にマージするよりも、より迅速に解決できます。
マージがわからない場合は、強制しないでください。
特に競合するファイルが多く、競合マーカーが数百行をカバーしている場合、マージは圧倒的に感じることがあります。 多くの場合、ソフトウェアプロジェクトを推定するときに、危険なマージの処理などのオーバーヘッドアイテムの十分な時間が含まれていないため、各競合を解剖するのに数時間費やすのは本当のドラッグのように感じます。
長期的には、事前に計画を立て、他の人が取り組んでいることに気づくことは、合併の対立を予測し、短時間でそれらを正しく解決するための最良のツールです。
1.どのファイルが競合しているかを特定する(Gitが教えてくれるはずです)。
1.各ファイルを開き、差分を調べます。Gitはそれらを区分けしています。 うまくいけば、各ブロックのどのバージョンを残すべきかは明らかでしょう。 そのコードをコミットした開発者仲間と議論する必要があるかもしれません。
1.ファイル内のコンフリクトを解消したら、git add the_file
.
1.競合をすべて解決したら、git rebase --continue
などのコマンドを実行します。
Gitは完成したときにやれと言った。
[スタックオーバーフロー]質問の回答を確認してください Gitでのマージの中止 、特にCharles Baileyの回答は、問題のあるファイルのさまざまなバージョンを表示する方法を示しています。
# Common base version of the file.
git show :1:some_file.cpp
# 'Ours' version of the file.
git show :2:some_file.cpp
# 'Theirs' version of the file.
git show :3:some_file.cpp
マージの競合は、ファイルに同時に変更が加えられたときに発生します。 それを解決する方法は次のとおりです。
git
CLI。矛盾した状態になったときに何をすべきかという簡単な手順は次のとおりです。
1。 競合ファイルのリストに注意してください: git status
( Unmerged paths
セクションの下)。
1。 次のいずれかのアプローチにより、ファイルごとに競合を個別に解決します。
-GUIを使用して競合を解決します: git mergetool
(最も簡単な方法)。
-リモート/その他のバージョンを受け入れるには、「git checkout --theirs path / file」を使用します。 これにより、そのファイルに対して行ったローカルの変更が拒否されます。
-ローカル/私たちのバージョンを受け入れるには、「git checkout --ours path / file」を使用します。
<sup>ただし、何らかの理由で競合が発生するリモートの変更があったため、注意が必要です。< / sup>。
関連:< https://stackoverflow.com/q/25576415/55075>。
-競合するファイルを手動で編集し、 <<<<<
/>>>>>
の間のコードブロックを探し、上または下からバージョンを選択します ====
。 参照:競合の提示方法。
-パスとファイル名の競合は、「git add/
git rm」で解決できます。
1。 最後に、「git status」を使用して、コミットする準備ができているファイルを確認します。
「アンマージドパス」の下にファイルがまだあり、競合を手動で解決した場合は、「git add path / file」で解決したことをGitに知らせてください。
1。 すべての競合が正常に解決された場合は、次のように変更をコミットします。「git commit -a」を使用して、通常どおりリモートにプッシュします。
参照:コマンドラインからのマージ競合の解決 GitHub。
実用的なチュートリアルの場合は、シナリオ5-カタコダによるマージコンフリクトの修正を確認してください。
Windows、macOS、Linux / Unixでファイルを視覚的に比較およびマージできるDiffMergeを正常に使用しました。
3つのファイル間の変更をグラフィカルに表示でき、自動マージ(安全な場合)と結果のファイルの編集を完全に制御できます。
。。
画像ソース:DiffMerge(Linuxスクリーンショット)< / sup>。
ダウンロードして、次のようにレポで実行します。
git mergetool -t diffmerge .
----------。
macOSでは、次の方法でインストールできます。
brew install caskroom/cask/brew-cask
brew cask install diffmerge
そしておそらく(提供されていない場合)PATHに配置された次の追加のシンプルなラッパーが必要です(例:. / usr / bin
):
#!/bin/sh
DIFFMERGE_PATH=/Applications/DiffMerge.app
DIFFMERGE_EXE=${DIFFMERGE_PATH}/Contents/MacOS/DiffMerge
exec ${DIFFMERGE_EXE} --nosplash "$@"
次に、次のキーボードショートカットを使用できます。
- ⁇ < / kbd>- Alt< / kbd>- Up< / kbd> / Down< / kbd>前/次の変更にジャンプします。 - ⁇ < / kbd>- Alt< / kbd>- Left< / kbd> / Right< / kbd>左または右からの変更を受け入れる。
または、opendiff(Xcode Toolsの一部)を使用して、2つのファイルまたはディレクトリをマージして、3番目のファイルまたはディレクトリを作成することもできます。
もしあなたが頻繁に小さなコミットをしているのなら、まず git log --merge
でコミットコメントを見ることから始めてください。それから git diff
を実行すると、コンフリクトが表示されます。
数行以上のコンフリクトの場合、外部のGUIツールで何が起こっているのかを確認する方が簡単です。私はopendiffが好きです -- Gitはvimdiff, gvimdiff, kdiff3, tkdiff, meld, xxdiff, emergeも標準でサポートしていますし、他のものをインストールすることもできます:git config merge.tool "your.tool"は選択したツールを設定し、マージに失敗した後に
git mergetool` を実行すると、差分を文脈で表示します。
競合を解決するためにファイルを編集するたびに、git add filename
によってインデックスが更新され、diff にはそれが表示されなくなります。すべてのコンフリクトが処理され、そのファイルが git add
されたら、git commit
でマージが完了します。
競合の提示方法、またはGitの「git merge」ドキュメントを参照して、マージの競合マーカーとは何か。
また、競合を解決する方法セクションでは、競合を解決する方法について説明します。
競合が発生した後、次の2つのことができます。
*マージしないことを決定します。 必要な唯一のクリーンアップは、インデックスファイルを「HEAD」コミットにリセットしてリバース2にすることです。 2によって行われた作業ツリーの変更をクリーンアップします。 および3。;これには「git merge --abort」を使用できます。
*競合を解決します。 Gitは作業ツリーの競合をマークします。 ファイルを編集して形にし、インデックスに「git add」します。 取引を成立させるには、「git commit」を使用します。
いくつかのツールを使用して、競合を解決できます。
- mergetoolを使用します。
git mergetool
は、マージを介して機能するグラフィカルマーゲットールを起動します。
*差分を見てください。
git diff
は、HEAD
バージョンとMERGE_HEAD
バージョンの両方からの変化を強調する3方向差分を表示します。
*各ブランチの差分を確認します。
git log --merge -p< path>
は、最初にHEAD
バージョンに差分を表示し、次にMERGE_HEAD
バージョンに差分を表示します。
*原文を見てください。
git show:1:filename
は共通の祖先を示し、git show:2:filename
はHEAD
バージョンを示し、git show:3:filename
はMERGE_HEAD
バージョンを示します。
Pro Gitの本のセクション[Basic Merge Conflicts](http://git-scm.com/ book/ch3-2.html#Basic-Merge-Conflicts)。
Emacsの場合、マージの競合を半手動で解決したいユーザー:
git diff --name-status --diff-filter=U
競合の解決が必要なすべてのファイルを表示します。
これらの各ファイルを1つずつ、または一度にすべて開きます。
emacs $(git diff --name-only --diff-filter=U)
Emacsで編集が必要なバッファにアクセスする場合は、入力します。
ALT+x vc-resolve-conflicts
これにより、3つのバッファー(鉱山、それらのバッファー、および出力バッファー)が開きます。 'n'(次の領域)、 'p'(準備領域)を押して移動します。 'a'と 'b'を押して、それぞれ鉱山または彼らの領域を出力バッファーにコピーします。 および/または出力バッファを直接編集します。
終了したら: 'q'を押します。 Emacsは、このバッファを保存するかどうかを尋ねます:はい。 バッファーを仕上げた後、テリミナルから実行して解決済みとしてマークします。
git add FILENAME
すべてのバッファタイプで終了したとき。
git commit
マージを終了します。
私またはそのバージョンを完全にしたい、または個々の変更を確認してそれぞれについて決定したい。
私または彼らのバージョンを完全に受け入れます:
私のバージョン(ローカル、私たちのバージョン)を受け入れます。
git checkout --ours -- <filename>
git add <filename> # Marks conflict as resolved
git commit -m "merged bla bla" # An "empty" commit
彼らのバージョン(リモート、彼らのもの)を受け入れる:
git checkout --theirs -- <filename>
git add <filename>
git commit -m "merged bla bla"
すべての競合ファイルに対して実行する場合は:を実行します。
git merge --strategy-option ours
または。
git merge --strategy-option theirs
すべての変更を確認し、個別に受け入れます。
1。 git mergetool
。
2。 変更を確認し、それぞれのバージョンを受け入れます。
4。 git add< filename>
。
5。 git commit -m "merged bla bla"
。
デフォルトの「mergetool」はコマンドラインで動作します。 コマンドラインmergetoolの使用方法は、別の質問である必要があります。
これにはビジュアルツールをインストールすることもできます。 「溶けて」走ります。
git mergetool -t meld
ローカルバージョン(ours)、「base」または「merged」バージョン(マージの現在の結果)およびリモートバージョン(theirs)を開きます。 完了したらマージバージョンを保存し、「ファイルをマージする必要なし」になるまでもう一度「git mergetool -t meld」を実行し、ステップ3に進みます。 および4。
簡単に言うと、いずれかのリポジトリの変更が重要ではないことをよく知っており、すべての変更を他の変更に有利に解決したい場合は、以下を使用します。
git checkout . --ours
リポジトリを優先して変更を解決するため、または。
git checkout . --theirs
その他またはメインリポジトリを優先して変更を解決します。
または、GUIマージツールを使用してファイルを1つずつステップアップしたり、マージツールが「p4merge」であるとしたり、すでにインストールした名前を書き込んだりする必要があります。
git mergetool -t p4merge
ファイルを完了した後、保存して閉じる必要があるため、次のファイルが開きます。
Gitでのマージ競合を修正するには、次の手順に従ってください。
1。 Gitステータスを確認します。 git status 。
2。 パッチセットを入手してください。 git fetch (Git commitから正しいパッチをチェックアウトします)。
3。 ローカルブランチをチェックアウトします(私の例では、ここでtemp1)。 git checkout -b temp1 。
4。 master:から最近のコンテンツを引き出します。 git pull --rebase origin master 。
5。 mergetoolを起動し、競合を確認して修正します。..現在のブランチでリモートブランチの変更を確認します。 git mergetool 。
6。 ステータスをもう一度確認してください。 git status 。
7。 mergetoolによってローカルに作成された不要なファイルを削除します。通常、mergetoolは* .orig拡張子を持つ追加のファイルを作成します。 複製なのでそのファイルを削除し、ローカルで変更を修正して、正しいバージョンのファイルを追加してください。 git add #your_changed_correct_files 。
8。 ステータスをもう一度確認してください。 git status 。
9。 同じコミットIDに変更をコミットします(これにより、新しい個別のパッチセットが回避されます)。 git commit --amend 。
10。 マスターブランチにプッシュ: git push (Gitリポジトリへ)。
上記の回答のプル/フェッチ/マージについて言えば、興味深い生産的なトリックを共有したいと思います。
git pull --rebase
#。この上記のコマンドは、多くの時間を節約した私のgitの人生で最も有用なコマンドです。
新しくコミットした変更をリモートサーバーにプッシュする前に、「git pull --rebase」ではなく「git pull」と手動の「merge」を試してください。これにより、最新のリモートサーバーの変更が(フェッチ+マージで)自動的に同期され、ローカルが配置されますgitログの上部にある最新のコミット。 手動のプル/マージを心配する必要はありません。
競合する場合は、使用してください。
git mergetool
git add conflict_file
git rebase --continue
詳細については、http://gitolite.com/git-pull--rebaseをご覧ください。
他の人が詳述しているように、いくつかの方法でマージの競合を修正できます。
本当の鍵は、ローカルおよびリモートリポジトリで変化がどのように流れるかを知ることだと思います。 これの鍵は、追跡ブランチを理解することです。 私は、追跡ブランチを、ローカルの実際のファイルディレクトリと、originとして定義されているリモートの間の「真ん中の欠けている部分」と考えることがわかりました。
私はこれを避けるために2つのことの習慣に個人的に入りました。
代わりに:
git add .
git commit -m"some msg"
これには2つの欠点があります。
a)すべての新規/変更されたファイルが追加され、不要な変更が含まれる場合があります。 b)最初にファイルリストを確認することはできません。
代わりに私はします:
git add file,file2,file3...
git commit # Then type the files in the editor and save-quit.
このようにして、追加されるファイルについてより慎重になり、メッセージにエディターを使用しながらリストを確認し、もう少し考えることができます。 -m
オプションではなくフルスクリーンエディターを使用すると、コミットメッセージも改善されます。
[更新-時間が経過したので、さらに次のように切り替えました。
git status # Make sure I know whats going on
git add .
git commit # Then use the editor
]。
また(そしてあなたの状況により関連しています)、私は避けようとします:
git pull
または。
git pull origin master.
pullはマージを意味し、マージしたくないローカルで変更がある場合、マージされたコードで簡単に終了したり、マージされるべきではなかったコードの競合をマージしたりできます。
代わりにやってみます。
git checkout master
git fetch
git rebase --hard origin/master # or whatever branch I want.
これも参考になるかもしれません。
CoolAJ86の答えは、ほとんどすべてを要約しています。 同じコードで両方のブランチに変更がある場合は、手動でマージする必要があります。 テキストエディターで競合ファイルを開くと、次の構造が表示されます。
(Code not in Conflict)
>>>>>>>>>>>
(first alternative for conflict starts here)
Multiple code lines here
===========
(second alternative for conflict starts here)
Multiple code lines here too
<<<<<<<<<<<
(Code not in conflict here)
等号と角括 ⁇ を削除しながら、新しいコードを希望するように、代替案の1つまたは両方の組み合わせを選択します。
git commit -a -m "commit message"
git push origin master
git log --merge -p [[--] path]
常にうまくいくとは限らず、通常は2つのブランチ間で異なるすべてのコミットを表示することになります。これは、 --
を使用してパスをコマンドから分離する場合でも発生します。
この問題を回避するために私が行うことは、2つのコマンドラインを開き、1回の実行で行うことです。
git log ..$MERGED_IN_BRANCH --pretty=full -p [path]
そしてもう一つ。
git log $MERGED_IN_BRANCH.. --pretty=full -p [path]
$ MERGED_IN_BRANCH
をマージしたブランチに置き換え、 [path]
を競合するファイルに置き換えます。 このコマンドは、パッチ形式のすべてのコミットを(。.
)2つのコミット。 上のコマンドのように片側を空のままにすると、gitは自動的に「HEAD」を使用します(この場合、マージするブランチ)。
これにより、2つのブランチが分岐した後、どのコミットがファイルに入ったかを確認できます。 通常、競合の解決がはるかに簡単になります。
マージ再帰戦略で「忍耐」を使用して紛争を解決することについて他の誰も話さなかったことに驚いています。 大きなマージ競合の場合、「忍耐力」を使用すると良い結果が得られました。 アイデアは、個々の行ではなくブロックを照合しようとすることです。
たとえば、プログラムのインデントを変更すると、デフォルトのGitマージ戦略が、異なる関数に属する単一の中かっこ {
と一致することがあります。 これは「忍耐」で避けられます:
git merge -s recursive -X patience other-branch
ドキュメントから:
With this option, merge-recursive spends a little extra time to avoid
mismerges that sometimes occur due to unimportant matching lines
(e.g., braces from distinct functions). Use this when the branches to
be merged have diverged wildly.
マージ競合があり、ブランチを変更するときに他の人が何を念頭に置いていたかを確認したい場合は、ブランチを共通の祖先(ブランチの代わりに)と直接比較する方が簡単な場合があります。 そのためには、「merge-base」:を使用できます。
git diff $(git merge-base <our-branch> <their-branch>) <their-branch>
通常、特定のファイルの変更のみを表示します。
git diff $(git merge-base <our-branch> <their-branch>) <their-branch> <file>
私は常に以下の手順に従って、競合を回避します。
-git checkout master(マスターブランチにお越しください)。 -git pull(最新のコードを取得するには、マスターを更新してください)。 -git checkout -b mybranch(新しいブランチをチェックアウトし、そのブランチで作業を開始して、マスターが常にトランクのトップに留まるようにします。)。 -git add。 . AND git commit AND git push(変更後のローカルブランチ)。 -git checkout master(マスターに戻ってください。)。
これで、同じようにして、必要な数のローカルブランチを維持し、同時に作業することができます。必要なときに、ブランチに対してgitチェックアウトを実行するだけです。