背景・目的
コンフリクトエラーが起きるような場面での新たな解決方法を知ったので共有します。
この記事はGit初学者向けです。
Gitのスタッシュの使い方を学ぼう
先生: こんにちは、生徒さん。今日はGitのスタッシュという機能について学びましょう。スタッシュとは、作業中の変更内容を一時的に退避させる機能です。スタッシュを使うと、コミットせずに別のブランチに切り替えたり、プルしたりすることができます。スタッシュした変更内容は、後で復元することができます。
生徒: なるほど、スタッシュとはそういうことなんですね。でも、どうしてそんなことをする必要があるんですか?
先生: いい質問ですね。例えば、あなたはfeatureブランチで新しい機能を開発しています。しかし、突然masterブランチに重要なバグ修正が入ったことを知りました。この場合、あなたはmasterブランチの最新の状態を取り込む必要があります。しかし、あなたはまだfeatureブランチで作業中で、コミットする準備ができていません。どうしますか?
生徒: えーと、コミットしないと別のブランチに切り替えられないんですよね? じゃあ、仕方なくコミットしてからmasterブランチに切り替えてプルしますか。
先生: それでもできなくはありませんが、あまりおすすめしません。なぜなら、コミットするときには意味のあるメッセージを付けるべきだからです。作業中の変更内容を適当にコミットすると、後でコミット履歴がわかりにくくなってしまいます。また、作業中の変更内容が不完全だったり、バグがあったりする可能性もあります。それをそのままプッシュしてしまうと、他の人に迷惑をかけることにもなりかねません。
生徒: そういうこともありますよね。じゃあ、どうすればいいんですか?
先生: そこでスタッシュの出番です。スタッシュを使えば、作業中の変更内容を一時的に退避させることができます。それでは、具体的な手順を見てみましょう。
1.まず、作業中のブランチで変更内容をステージングエリアに追加します。例えば、README.mdとindex.htmlという2つのファイルを変更したとします。その場合、次のコマンドを実行します。
git add README.md index.html
2.次に、スタッシュを作成します。スタッシュには任意のメッセージを付けることができます。
3.メッセージを付けると、後でスタッシュの内容を確認しやすくなります。例えば、次のコマンドを実行します。
git stash save "update README and index"
4.スタッシュが作成されたら、別のブランチに切り替えたり、プルしたりすることができます。例えば、masterブランチに切り替えてプルする場合は、次のコマンドを実行します。
git checkout master
git pull
5.スタッシュした変更内容を復元するには、スタッシュを適用します。スタッシュを適用する前に、作業中のブランチに戻る必要があります。例えば、次のコマンドを実行します。
git checkout feature
git stash apply
6.スタッシュを適用したら、変更内容がステージングエリアに戻されます。その後、コミットやプッシュなどを行うことができます。例えば、次のコマンドを実行します。
git commit -m "update README and index"
git push origin feature
7.スタッシュは適用しても削除されません。不要になったスタッシュは削除することができます。スタッシュは作成された順に番号が付けられます。最新のスタッシュはstash@{0}という名前になります。スタッシュの一覧はgit stash listコマンドで確認できます。例えば、次のコマンドを実行します。
git stash list
stash@{0}: On feature: update README and index
stash@{1}: On master: fix bug
stash@{2}: On develop: add feature
8.スタッシュを削除するには、git stash dropコマンドを使います。削除するスタッシュの名前を指定します。例えば、最新のスタッシュを削除する場合は、次のコマンドを実行します。
git stash drop stash@{0}
先生: 以上が、スタッシュの使い方の具体例です。分かりやすかったでしょうか?
生徒:はい、ありがとうございました!
質問コーナー
はじめにgit addが必要なのですか?
先生:
はい、そうです。スタッシュはステージングエリアにある変更内容だけを退避させるので、git addが必要です。もし、ステージングエリアに追加しない変更内容もスタッシュしたい場合は、git stash -uコマンドを使うことができます。
commit時にコンフリクトは起きないのでしょうか?
先生:
コンフリクトとは、同じファイルの同じ箇所を異なる内容で変更した場合に起こる現象です。コンフリクトが起こると、Gitはどちらの変更内容を優先すべきか判断できません。そのため、手動で修正する必要があります。
スタッシュを適用するときにも、コンフリクトが起こる可能性があります。例えば、あなたがスタッシュした後に、他の人が同じファイルの同じ箇所を変更してプッシュした場合です。この場合、あなたがスタッシュを適用しようとすると、コンフリクトが発生します。その場合は、次のようなメッセージが表示されます。
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
このメッセージは、index.htmlというファイルでコンフリクトが起こったことを示しています。この場合は、index.htmlを開いて、コンフリクト箇所を探します。コンフリクト箇所は、次のような記号で囲まれています。
<<<<<<< Updated upstream
<p>This is the original version.</p>
=======
<p>This is the stashed version.</p>
>>>>>>> Stashed changes
この記号の間にある内容がコンフリクトしている内容です。上側のUpdated upstreamという部分が現在のブランチの内容で、下側のStashed changesという部分がスタッシュした内容です。この場合は、どちらか一方の内容を残すか、両方を組み合わせるか、新しい内容に書き換えるかなど、自分で修正する必要があります。
コンフリクト箇所を修正したら、再度git addとgit stash dropを実行します。これでスタッシュを適用することができます。
Gitのチェリーピックを学ぼう
先生: チェリーピックとは、特定のコミットだけを別のブランチに適用する機能です。チェリーピックを使うと、ブランチ間で必要な変更だけを移動したり、マージすることができます。
生徒: なるほど、チェリーピックとはそういうことなんですね。でも、どうしてそんなことをする必要があるんですか?
先生: いい質問ですね。例えば、あなたはdevelopブランチで新しい機能を開発しています。しかし、その途中でmasterブランチに重要なバグ修正が入ったことを知りました。この場合、あなたはmasterブランチの最新の状態を取り込む必要があります。しかし、あなたはまだdevelopブランチで作業中で、マージする準備ができていません。どうしますか?
生徒: えーと、マージしないと別のブランチの変更内容を取り込めないんですよね? じゃあ、仕方なくマージしてからdevelopブランチに戻しますか。
先生: それでもできなくはありませんが、あまりおすすめしません。なぜなら、マージするときには意味のあるメッセージを付けるべきだからです。作業中の変更内容を適当にマージすると、後でコミット履歴がわかりにくくなってしまいます。また、作業中の変更内容が不完全だったり、バグがあったりする可能性もあります。それをそのままプッシュしてしまうと、他の人に迷惑をかけることにもなりかねません。
生徒: そういうこともありますよね。じゃあ、どうすればいいんですか?
先生: そこでチェリーピックの出番です。チェリーピックを使えば、特定のコミットだけを別のブランチに適用することができます。それでは、具体的な手順を見てみましょう。
1.まず、適用したいコミットのハッシュ値を確認します。ハッシュ値とは、コミットに付けられる一意の識別子です。ハッシュ値はgit logコマンドで確認できます。例えば、次のコマンドを実行します。
git log --oneline
2.次に、コミットを適用したいブランチに切り替えます。例えば、developブランチに切り替える場合は、次のコマンドを実行します。
git checkout develop
3.次に、チェリーピックを実行します。チェリーピックするコミットのハッシュ値を指定します。例えば、masterブランチで行われたバグ修正のコミットがa1b2c3d4というハッシュ値だった場合は、次のコマンドを実行します。
git cherry-pick a1b2c3d4
4.チェリーピックを実行したら、指定したコミットが現在のブランチに適用されます。その後、プッシュなどを行うことができます。例えば、次のコマンドを実行します。
git push origin develop
先生: 以上が、チェリーピックの使い方の具体例です。
質問コーナー Part2
いまいちチェリーピックとスタッシュの使い分けがわかりません。どういう場面でどちらを使うべきでしょうか。
先生: チェリーピックとスタッシュは、似ているようで実は違う機能です。チェリーピックは、特定のコミットだけを別のブランチに適用する機能です。スタッシュは、作業中の変更内容を一時的に退避させる機能です。
生徒: なるほど、チェリーピックはコミット単位で、スタッシュは変更内容単位で動くんですね。
先生: そうです。チェリーピックは、コミット履歴を残すことができます。スタッシュは、コミット履歴を残しません。
生徒: なるほど、チェリーピックはコミット履歴を残すことができるんですね。
先生: そうです。では、どういう場面でどちらを使うべきでしょうか。一般的には、次のような基準で使い分けることができます。
■チェリーピックを使う場面
・別のブランチにある特定のコミットだけを取り込みたい場合
・コミット履歴を残したい場合
・変更内容が完全でバグがない場合
■スタッシュを使う場面
・作業中のブランチで変更内容を一時的に退避させたい場合
・コミット履歴を残したくない場合
・変更内容が不完全でバグがある場合
生徒: なるほど、チェリーピックとスタッシュの使い分け方がわかりました。ありがとうございます。
先生: どういたしまして。これでチェリーピックとスタッシュの違いと使い分け方についての説明を終わります。
チェリーピックした際に、自分が編集しているファイルも変更されていてコンフリクトが起きていた場合どうすればいいですか。
先生: チェリーピックを実行するときにも、コンフリクトが起こる可能性があります。例えば、あなたがdevelopブランチでindex.htmlというファイルを編集しています。しかし、masterブランチで行われたバグ修正のコミットにもindex.htmlというファイルが含まれています。この場合、あなたがそのコミットをチェリーピックしようとすると、コンフリクトが発生します。その場合は、次のようなメッセージが表示されます。
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
このメッセージは、index.htmlというファイルでコンフリクトが起こったことを示しています。この場合は、index.htmlを開いて、コンフリクト箇所を探します。コンフリクト箇所は、次のような記号で囲まれています。
<<<<<<< HEAD
<p>This is the develop version.</p>
=======
<p>This is the master version.</p>
>>>>>>> a1b2c3d4
この記号の間にある内容がコンフリクトしている内容です。上側のHEADという部分が現在のブランチの内容で、下側のa1b2c3d4という部分がチェリーピックしたコミットの内容です。この場合は、どちらか一方の内容を残すか、両方を組み合わせるか、新しい内容に書き換えるかなど、自分で修正する必要があります。
コンフリクト箇所を修正したら、再度git addとgit cherry-pick --continueを実行します。これでチェリーピックを完了することができます。
生徒: なるほど、チェリーピック時にコンフリクトが起こった場合の対処法がわかりました。ありがとうございます。
先生: どういたしまして。これでチェリーピック時にコンフリクトが起こった場合の対処法についての説明を終わります。