Gitマージコンフリクトとは何ですか?
Gitバージョン管理システムは、チームとしてプロジェクトに貢献することに重点を置いています。開発者は通常、孤立したブランチで作業し、作業が完了すると変更をメインブランチにマージします。このようなチームワークは非常に生産的で、バグを見つけるのに効果的です。時々、複数の開発者が同じコード行に取り組んでおり、変更をマージしようとするとコンフリクトが発生します。
Gitコンフリクトの簡単な例
上の図は、一般的なGitのマージコンフリクトの例を示しています。メインブランチには「HELLO, WORLD!」というテキストを含むファイルがあり、ユーザーabidがメインブランチをフォークし、テキストを「HELLO, CAT!」に変更します。abidが変更を行う間、元のメインブランチは「HELLO, DOG!」に変更されます。これらのブランチをマージすると、マージコンフリクトの問題が発生し、プロセスを一時中断します。
`git merge`コマンドの主要な仕事は、2つのブランチを結合し、コンフリクトを自動的に解決することです。しかし、時々2人が同じ行のコードを変更したり、他の開発者が作業中の重要なファイルを削除したりするコンフリクトが現れます。Gitはこれらの変更をマークし、マージのプロセスを止めます。この場合、コンフリクトは自動的に解決されず、開発者は手動で変更を行い、コンフリクト解決ツールを使用しなければならないです。
マージタイプ
Git mergeとrebaseは、対象ブランチから源ブランチにコミットを統合する2つの方法です。また、Git mergeはファストフォワードマージやノーファストフォワードマージを行います。対象ブランチのヘッドが源ブランチに存在する場合、デフォルトでファストフォワードマージとなり、存在しない場合はノーファストフォワードマージとなります。Git rebaseは、他の種のマージで、対象ブランチのコミット履歴を再 sequencing します。
ファストフォワードマージ
Gitのマージはデフォルトでフォワードマージを使用してターゲットブランチに不足しているコミットを統合します。例えば、プルコマンドを使用してリモートサーバーからローカルブランチを更新する際に使用されます。フォワードマージは、ソースブランチにターゲットブランチの先頭がない場合にGitが適用しないため、マージの衝突問題を引き起こしません。
非フォワードマージ
非フォワードマージは、3方向マージや真のマージとも呼ばれます。これは、ソースブランチとターゲットブランチの両方の変更を統合して、ターゲットブランチに新しいコミットを作成します。変更は、両ブランチで最後の共通コミットの後で混在されます。私たちのケースでは、Cの後です。このタイプのマージは、ソースブランチがターゲットブランチと競合している場合にGitマージコンフリクトを表示します。上の図では、マージコミット(X)はソースとターゲットブランチを統合して作成され、KとEはマージコミットの親です。
リベース
Gitのリベースは他のタイプとは少し異なります。これはターゲットブランチのコミット履歴のシーケンスを変更します。リベースは、ソースブランチを統合して、ターゲットブランチが最後の共通コミットCの後のソースブランチのすべての変更を含んだ後、すべてのターゲットブランチのコミットを継続するように統合します。私たちのケースでは、DとEはソースブランチから来ており、K*コミットはKと同じで、異なるコミットIDを持っています。Cをリンクする代わりにEをリンクします。非フォワードマージと同様に、ソースとターゲットブランチに互換性の問題がある場合、Gitはリベースを完了する前に解決するための問題を引き起こします。
Gitマージコンフリクトの種類
Gitのマージコンフリクトには、開始時とマージ過程中等の2種類があります – Atlassian。このセクションでは、この2つの種類とそれぞれの解決方法を学びます。
マージ開始時のコンフリクト
Gitのマージは、作業ディレクトリやステージングエリアに変更がある場合、開始時に失敗することがあります。これは、入力のマージコミットによって変更が上書きされるのを防ぐための措置です。これは、他のブランチや開発者との衝突ではなく、ローカル変更との衝突によるものです。稳固なローカル状態を得るためには、git stash
、git commit
、git checkout
、またはgit reset
のようなコマンドが使えます。
マージ過程中等のコンフリクト
マージ中の失敗は、源と目标のブランチで同じファイルに複数の開発者が変更したことによるコンフリクトがあることを意味します。自動的なマージが失敗すると、Gitは手動で問題解決を求めます。また、3rd partyツールを使用して、変更の視覚化と統合を助けることもできます。
Gitマージコンフリクトの解決コマンド
このセクションでは、Gitのマージコンフリクトを視覚化し、解決するための様々なネイティブコマンドを学びます。
一般的なコマンド
Git statusは、最も頻繁に使用されるコマンドで、変更されたファイル、ステージングエリア、コミットの状態を表示します。マージプロセスの間、衝突したファイルを特定するためにも使用されます。
git status
Gitのログで、–merge引数を使用することで、源のブランチと衝突しているコミットのリストを生成します。
git log --merge
デフォルトで、git diff
オプションは、未コミットの変更と以前のコミットの間の差分を表示します。Git diffは、ブランチ、コミット、およびファイルを比較し、将来のマージコンフリクトを防ぐのに有用です。
git diff
マージ失敗のための開始時のコマンド
Checkoutは、変更を取り消すか新しいまたは古いブランチに切り替えるために使用されます。
git checkout
Git resetは、作業ディレクトリとステージングエリアの変更を元に戻すために使用されます。
git reset --mixed
マージ中のコンフリクトのためのコマンド
–abort引数は、マージプロセスを停止し、マージ開始前の状態に変更を元に戻します。
git merge --abort
Git resetは、マージプロセス中に通常使用され、衝突したファイルを元の状態に戻すために使用されます。
git reset
削除された変更されたファイルのコンフリクトを解決する
Gitコンフリクトが起こる場合、現在のブランチでファイルを削除し、他の人が他のブランチで変更している場合。この場合、ファイルを追加してコミットすることができます。
git add <filename>
また、ファイルを削除してコミットすることもできます。
git rm <filename>
ビジュアルマージツール
マージツールは、マージコンフリクトを特定および解決するためのユーザーフレンドリーなビジュアルツールです。一部のツールは、変更点の比較、Git操作、プロジェクトとリポジトリ管理などの追加機能をサポートしています。Gitマージツールには、端末専用とGUIベースの2種類があります。端末ベースのツールはPowerShellまたはBashで開かれ、GUIベースのツールはウィンドウ環境で開かれます。
インストールされて有効なツールの一覧を確認するには、以下を使用します。
git mergetool --tool-help
この一覧には、gitコマンドと統合できる全ての有効なツールが含まれています。
たとえば、vimとnvimはデフォルトでインストールされており、未コミットのファイルと前のコミットの差分を見たい場合は、以下のように入力します。
git difftool --tool=vimdiff3
vimdiff3ツールは変更点をハイライトし、端末内でコミットの比較を行います。
Vimdiff3で同じファイルの2つのバージョン間の差分
Meld
Meldは、マージコンフリクトの解決を別のレベルに持って行く無料でオープンソースのツールです。Gitと統合するには、まず公式サイトからダウンロードして設定をインストールし、次にグローバル設定に追加しておく必要があります。そうすることで、デフォルトでGitがMeldを起動してコンフリクト解決を行います。
以下の設定コマンドはWindowsユーザー専用です。変更する必要があるのは、MeldのインストールファイルのパスをMacやLinux用に変更することだけです。
git config --global merge.tool meld git config --global mergetool.meld.path "C:/Program Files (x86)/Meld/Meld.exe" git config --global diff.tool meld git config --global difftool.meld.path "C:/Program Files (x86)/Meld/Meld.exe"
既定の設定後、Gitのローカルディレクトリ内でgit difftool
を入力することで、Windows版のMeldを起動することができます。以下のように、git mergetool
を使用してマージコンフリクトを解決することもできます。
Meldを使用したマージコンフリクトの解決
VSCode
VSCodeは、マージコンフリクトの解決に最も適し、最も人気のある方法を提供します。Gitが自動的にファイルをマージすることができない場合、VSCodeは衝突したコードを強調表示し、以下の4つの選択肢を提供します:現在の変更を接受、入力する変更を接受、両方の変更を接受、変更を比較する。これらの選択肢を使用して、ファイルを整理し、すべての未解決問題を解決することができます。
VSCodeを使用したマージコンフリクトの解決
Git操作の完全な解決策を探している場合、GitKrakenを試してみてください。これには、無料のクライアント、VSCodeエクステンションが含まれ、マージコンフリクトの解決に使用される内蔵ツールがあります。
Gitのマージコンフリクトを解決する方法
このセクションでは、Gitのマージコンフリクトを作成し、それを解決する方法を学びます。チュートリアルは2部分に分かれています。最初の部分では、Gitのコンフリクトをローカルに解決する方法を学び、2番目の部分はリモートサーバー(GitHub)でのコンフリクト解決についてです。
ローカルマージコンフリクト
マージコンフリクトを作成することで、どのようにしてこれらの問題が発生するのかを学びます。それから、これらの問題を解決する創造的な方法や、将来発生するのを防ぐ方法を探ることができます。
Gitリポジトリを作成し、1つのファイルに最初のコミットを行い、始めましょう。
- datacampという名前のフォルダーを作成します。
- datacampにディレクトリを変更します。
- Gitを初期化します。
- 与えられたタイトルのREADME.mdファイルを作成します。
- 変更をステージングし、ファイル内でコミットします。
mkdir datacamp cd datacamp git init echo "# How to Resolve Git Merge Conflict" > README.md git add README.md git commit -m "first commit" >>> [main (root-commit) 8199ea2] first commit >>> 1 file changed, 1 insertion(+) >>> create mode 100644 README.md
次に、readmeという新しいブランチを作成し、「..Git Merge..」から「..Git..」にタイトルを変更します。-am引数を使ってファイルを追加し、コミットを作成します。
git checkout -b readme echo "# How to Resolve Git Conflict" > README.md git commit -am "new branch conflict added" >>> [readme 155f694] new branch conflict added >>> 1 file changed, 1 insertion(+), 1 deletion(-)
メインブランチに戻り、>>を使ってREADME.mdに新しい行を追加します。変更を保存し、コミットを作成することで、同じファイルの2つのバージョン間のコンフリクトを成功적に形成しました。
git checkout main echo "New change in base branch" >> README.md git commit -am " a line added to base branch Readme file" >>> [main f1f1874] a line added to base branch Readme file >>> 1 file changed, 1 insertion(+)
ご覧の通り、readmeブランチをマージする際、Gitは自動マージが失敗したことを示すメッセージを表示し、手動で変更を行い、その結果をコミットする必要があることを通知します。
git merge readme >>> Auto-merging README.md >>> CONFLICT (content): Merge conflict in README.md >>> Automatic merge failed; fix conflicts and then commit the result.
私たちは、Notepadを使ってファイルを開いて編集して、手動で問題を解決する。以下の画像は、HEADの矢印、区切り線、readmeの矢印(方向が異なる)を示しています。HEAD部分は、メインブランチの既存の変更を示しています。readme部分は、取り込みたいブランチであり、異なる見出しを構成しています。
手動でマージコンフリクト解決
問題を解決するためには、readmeブランチ部分、矢印、区切り線を削除する必要があります。最終的なファイル版は、以下のように清潔になるべきです。
コンフリクト解決
ファイルを追加し、コミットを作成する後、マージコンフリクトは解決されます。これは、最も一般的で最も簡単な方法で問題を解決することです。IDEを使用することもでき、問題をより早く解決することができます。
git commit -am "conflict resolved in file README.md" >>> [main 9994a29] conflict resolved in file README.md
リモートマージコンフリクト
リモートマージコンフリクトを作成および解決するためには、GitHubに新しいリポジトリを作成する必要があります。
GitHubで新しいリポジトリを作成する
リポジトリにリモート名(origin)とアドレスを追加し、ローカルリポジトリから全ての変更をアップストリームによってリモートのメインブランチにプッシュします。
git remote add origin https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git git push --set-upstream origin main >>> Enumerating objects: 12, done. >>> Counting objects: 100% (12/12), done. >>> Delta compression using up to 4 threads >>> Compressing objects: 100% (6/6), done. >>> Writing objects: 100% (12/12), 998 bytes | 499.00 KiB/s, done. >>> Total 12 (delta 2), reused 0 (delta 0), pack-reused 0 >>> remote: Resolving deltas: 100% (2/2), done. >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> * [new branch] main -> main >>> branch 'main' set up to track 'origin/main'.
競合を作成するために、リモートとローカルのREADME.mdファイルに変更を加える必要があります。GitHubのファイルエディタを使用して「..Git merge..」を「..Sit-Merge..」に変更し、変更内容をコミットすることができます。
GitHubエディタでの変更
次に、ローカルリポジトリ内のREADME.mdファイルに単純なタイトルを追加するだけの変更を加え、変更内容をコミットします。
echo "# How to Resolve Merge Conflicts in Git Tutorial" > README.md git commit -am "local branch changes in README.md" >>> [main c677a13] local branch changes in README.md >>> 1 file changed, 1 insertion(+), 4 deletions(-)
最後に、変更をリモートサーバーにプッシュします。Gitがエラーを発生させ、問題解決のヒントを提供することに注意してください。
git push >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> ! [rejected] main -> main (fetch first) >>> error: failed to push some refs to 'https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git' >>> hint: Updates were rejected because the remote contains work that you do >>> hint: not have locally. This is usually caused by another repository pushing >>> hint: to the same ref. You may want to first integrate the remote changes >>> hint: (e.g., 'git pull ...') before pushing again. >>> hint: See the 'Note about fast-forwards' in 'git push --help' for details.
最も簡単なヒントに従い、プッシュする前にリモートサーバーからファイルをプルします。
README.mdファイルのマージ競合のためにプルに失敗しました。Notepadで手動で修正できますが、今回は視覚的なツールを使用してこのプロセスを助けます。
git pull >>> remote: Enumerating objects: 5, done. >>> remote: Counting objects: 100% (5/5), done. >>> remote: Compressing objects: 100% (2/2), done. >>> remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 >>> Unpacking objects: 100% (3/3), 681 bytes | 75.00 KiB/s, done. >>> From https://github.com/kingabzpro/DataCamp-Git-Merge-Guide >>> aaf149d..49b7d14 main -> origin/main >>> Auto-merging README.md >>> CONFLICT (content): Merge conflict in README.md >>> Automatic merge failed; fix conflicts and then commit the result.
マージツールMeldは競合のあるファイルを特定し、Meld GUIアプリケーションに表示します。
git mergetool >>> Merging: >>> README.md >>> Normal merge conflict for 'README.md': >>> {local}: modified file >>> {remote}: modified file
3つの列があります:README_LOCAL_473.md、README.md、README_LOCAL_473.md。リモートの変更が有効であると思われる場合は、リモート列の黒い矢印をクリックし、ローカルの変更を保持したい場合は、ローカル列の黒い矢印をクリックします。それだけ簡単です。
Meldを使用した衝突解決
変更を行った後、ファイルを保存しコミットしてください。ご覧のように、ファイルを远隔サーバにプッシュすることで、マージ衝突エラーが発生しないことがわかります。
git commit -am "remote main branch conflict resolved" git push >>> Enumerating objects: 16, done. >>> Counting objects: 100% (16/16), done. >>> Delta compression using up to 4 threads >>> Compressing objects: 100% (6/6), done. >>> Writing objects: 100% (10/10), 1.08 KiB | 550.00 KiB/s, done. >>> Total 10 (delta 2), reused 0 (delta 0), pack-reused 0 >>> remote: Resolving deltas: 100% (2/2), completed with 1 local object. >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> 49b7d14..8f5c3aa main -> main
私たちは、ローカルと远隔サーバのマージ衝突を成功に解決しました。これらの衝突は、データ科学者と機械学習エンジニアが日常的に取り扱っています。Git操作のスキルを向上させるために、Gitの入門コースを取るとより良いです。
結び
Gitのマージコンフリクト解決は、缺陷のコードをマージすることでソフトウェアを壊すことができるとても複雑で危険な任务です。マージツールは、マージコンフリクトを検出および解決するためにより安全な方法を提供し、ユーザーフレンドリーな環境を提供します。このチュートリアルでは、Gitコンフリクトがどのように発生するのかとなぜそれらを解決するかを学びました。また、様々なマージとコンフリクトのタイプ、便利なGitコマンド、ビジュアルツールについてもご説明しました。最終セクションで、ローカルと远隔リポジトリにマージコンフリクトを作成し、解決しました。
Gitに新しいところではない場合、GitとGitHubを学ぶためには、GitとGitHubの入門チュートリアルを読むとより良いです。
Source:
https://www.datacamp.com/tutorial/how-to-resolve-merge-conflicts-in-git-tutorial