シナリオ:2 人が同じ Git ブランチを管理するシミュレーション。
まず、Github リポジトリで master
を基に新しいブランチ feature/add_git_cmds
を作成し、Create branch をクリックします:
作成が成功したら、ローカルに戻り、ローカルで 2 つのリポジトリをプルして、2 人の開発をシミュレートします。
2 人に異なる user を設定するのを忘れないでください~
まず、Git リポジトリのグローバル設定( --global
)を確認しましょう:
git_learning_A にはデフォルトのグローバルユーザー設定を使用させ、git_learning_B にはローカルユーザー設定( --local
、グローバル設定より優先)を設定します:
(設定は1 Git 基礎 --03|git を使用する前に必要な最小設定)を参考にしてください。
最後に、2 つのローカルリポジトリで、リモートのfeature/add_git_cmds
ブランチを基に関連付けられたローカルブランチを作成します。
コマンド: git checkout -b feature/add_git_cmds origin/feature/add_git_cmds
、このコマンドは後ろのリモートブランチを基に前者の名前のローカルブランチを作成し、リモートブランチを追跡し、新しく作成したブランチに切り替えます。
2 つのローカルリポジトリで同様の操作を行います。
これで、2 人が同じリポジトリの同じブランチで開発するシナリオをシミュレートしました。次に、5 つの状況について一つずつ実験してみましょう🧪!
34 | 異なる人が異なるファイルを変更した場合はどう処理する?#
結論:そのままマージすれば良いです。
git_learning_A:readme.md ファイルを変更し、リモートにプッシュします。
git push
は順調に進みました。
リモートリポジトリを確認します:
コミット履歴の著者を確認すると、git_learning_A が使用しているグローバルユーザー設定に対応しています:
git_learning_B:別のファイル xxx/css.x を変更し、プッシュする前にまずプルし、次にプッシュを試みます。
まずファイルを変更し、直接プッシュしてみると、何が起こるでしょうか?
前のステップは git_learning_A と似ていますが、 git push
の際に予期しない事態が発生しました。これは見覚えがありますか?エラーは前の章で言及したものと全く同じです:3 Git と GitHub の簡単な同期 --33 | ローカルリポジトリを GitHub に同期する。
❌: git push -f
強制プッシュ。
✅:まずプルし、次にマージし、最後にプッシュします。
git fetch
:
最新のコミットのハッシュ値が d7d648a から 192a3b3 に更新されたことがわかります。
ブランチの説明で、現在のブランチとリモートブランチの状態は:ahead 1(ローカルに更新があり、リモートにプッシュしていない)、behind 1(リモートに更新があり、ローカルに取り込んでいない)ですので、まずマージを行います。
git merge origin/feature/add_git_cmds
:
実行後、コミットメッセージの編集がポップアップし、デフォルトのままで良いか、適宜説明を追加します。
:wq
で保存して終了すると、マージが成功し、変更の記録が確認できます。
青い線で現在の状態が ahead 2 であることがわかります。つまり、ローカルには 2 つのコミットがあり、まだリモートにプッシュされていません;
赤い枠は ahead の 2 つのコミット記録です。
この時点で、ローカルの readme.md と xxx/css.x ファイルはどちらも変更後の状態になっており、次にそのままプッシュすれば良いです。
git push
:
プッシュ成功!異なる人が異なるファイルで協力して作業するのは非常に便利ですので、協力作業はこの方法で行うのが非常に効率的ではないでしょうか?他の状況も見てみましょう~
35 | 異なる人が同じファイルの異なる領域を変更した場合はどう処理する?#
結論:そのままマージすれば良いです。
⚠️:まず異なる領域の環境を作成し、いずれかのリポジトリの readme.md ファイルに複数行を追加し、プッシュして、2 つのリポジトリを同期させます。readme.md ファイルの変更は以下の通りです:
前のセクションのファイルは 1 行しかなかったため、異なる領域を変更することはできませんでした。
git_learning_A:readme.md の 4 行目を変更し、そのままプッシュします。
git_learning_B:readme.md の 7 行目を変更し、まずプルしてからプッシュします。
git pull
の過程で、コミットメッセージの編集がポップアップし、 :wq
で保存して終了すると、マージが成功します。
⚠️:ここで直接プルすると、明確なプル戦略がないため推奨されません。
1)プルのデフォルト戦略を手動で設定できます。
2)または、 git pull
コマンドの後にオプションを追加します。例えば --rebase
、 --no-rebase
、 --ff-only
など。
3)または、 git fetch
を使用した後、マージ戦略を選択します。
この時点でローカルの readme.md ファイルを確認すると、期待通りの内容になっており、そのままプッシュすれば良いです:
この方法での協力作業も比較的スムーズで、Git は自動的にマージする能力を持っています~
36 | 異なる人が同じファイルの同じ領域を変更した場合はどう処理する?#
結論:マージ時に衝突が発生し、自分で解決する必要があります。
git_learning_A:readme.md の 1 行目を変更し、そのままプッシュします。
⚠️:まず git pull
を行うのを忘れないでください。なぜなら、先ほど git_learning_B が行った更新がまだ同期されていないからです。
git_learning_B:同様に readme.md の 1 行目を変更し、まずプルしてから手動で衝突を解決し、次にプッシュします。
今回は git pull
にオプション --no-rebase
を付けて、マージ方式でプルを行いました。
その後、衝突が発生し、衝突を自分で解決する必要があります。
vim readme.md
で衝突が発生したファイルを開きます:
衝突が発生した位置には明確なマークがあり、HEAD と === の間はローカルのコード、ハッシュ値と === の間はマージされたコードを示しています。
この部分のコードを修正し、これらの特殊なマークを削除する必要があります。以下のように修正できます:(実際の開発では、関連する人とコミュニケーションを取ってから修正してください❗️)
:wq
で保存して終了した後、 git status
でリポジトリの状態を確認します:
赤い枠の上側はマージを行うことを示し、下側はマージをキャンセルして、マージ前の状態に戻ることを示しています。
ここで上側を実行してみましょう。⚠️:この時点での変更は作業ツリーにあり、まずはステージングエリアに追加し、次にコミットする必要があります。
まず追加してコミットし、その後プッシュします:
PS: -am
は追加とコミットの 2 つの操作を含みます。
今回は Git がそれほど賢くないことがわかりました。また、そんなに賢くある必要もありません。なぜなら、誰のコードが保持されるべきかを Git は知ることができないからです。
37 | 同時にファイル名とファイル内容を変更した場合はどう処理する?#
結論:そのままマージすれば良いです。
git_learning_A:xxx/css.x のファイル名を xxx/css2.x に変更します。
git mv
コマンドを覚えていますか?1 Git 基礎 --06 | ファイルをリネームする簡便な方法を振り返ってみてください。
git_learning_B:xxx/css.x の内容を変更します(ファイル名が既に変更されていることは知らない)。
素晴らしい~Git はこのような問題を自動的に解決できます。マージの状況を確認します:
ファイル名が変更されたことだけでなく、ファイル内の変更も保持されていることがわかります。
本質的に、ここで変更されているのは同じファイルの異なる領域です~
38 | 同じファイルを異なるファイル名に変更した場合はどう処理する?#
結論:マージ時に衝突が発生し、自分で解決する必要があります。
git_learning_A:xxx/css2.x のファイル名を xxx/cssA.x に変更します。
git_learning_B:xxx/css2.x のファイル名を xxx/cssB.x に変更します。(ファイル名が既に変更されていることは知らない)。
衝突が発生しました~
ファイルの状況を確認します:
Git の処理は両方の変更されたファイル名を同時に保持することであり、2 つのファイルの内容には違いがありません。
git status
でもファイル名の変更状況が明確に示され、どのように処理すべきかもわかります。
git rm
で不要なファイルを削除し、 git add
で最終的に必要なファイルを決定し、コミットしてプッシュすれば良いです!
これらのシナリオでの Git による協力作業を見て、衝突の解決がもはや恐れるべきことではなくなったのではないでしょうか?