変更をマージしよう
今回は変更をマージする方法について解説します。
マージは複数人で開発する上で必須のスキルになってきますので、しっかり押さえておきましょう。
マージとは何か。
マージとは他の人の変更内容を取り込む作業のことを言います。
他の人の変更内容を自分のブランチに取り込む(統合)することになります。
マージするコマンドについて見ていきましょう。
マージは
$ git merge <ブランチ名>
もしくは
$ git merge <リモート名/ブランチ名>
というコマンドでマージすることができます。
コマンド自体の名前はそのままですね。
例えば
$ git merge origin/main
というように入力します。
すると、origin(GitHubのこと)のmainブランチの内容を自分の作業中のブランチにマージします。
ではこれをイメージで押さえておきましょう。
今状況として、mainブランチとfeatureブランチというのがあります。
そのfeatureブランチの内容をmainブランチにマージしていこうと思います。
その場合のコマンドとしては
$ git merge feature
と入力します。
すると何が起こるのかというと、mainブランチの内容にfeatureブランチの内容が統合されて、新しく統合されたコミットができます。
このコミット「6847g」というコミットは元々のmainブランチの内容をベースにfeatureブランチの変更分を取り込んだ内容になります。
このようにマージすることで、他のブランチの内容を取り込むことができました。
マージをしてブランチの変更分を取り込む際に、取り込み方には3種類あります。
この3種類の区分けがしっかりできると、マージの裏側で実際に何が起こっているのかがわかるようになります。
すると、マージした時に何が起こっているのかわからないと言うことが無くなるので、そんなに重要ではないのですが、理解はするようにしておいてください。
1つ目がFast Fowardという種類になります。
これは早送りになるマージと呼ばれています。
どういうことかというと、今mainブランチがあったとします。
その状態から緊急のバグが発生して、それを急遽修正しないといけないという状況になったとしましょう。
その場合、hotfixというブランチを新たに作成して、修正してコミットします。
その修正内容をmainブランチに取り込んでいきます。
mainブランチに取り込むためには「git merge hotfix」と入力します。
すると何が起こるのかというと、mainブランチが指すコミットファイルが「23q1a」というhotfixと同じ物を指すようになります。
これはどういうことかというと、hotfixが指しているコミットとmainが指しているコミットファイルが一緒のものになった。
つまり、mainというブランチが指しているポインタが指しているコミットファイルというのが、単純にポインタが前に進んだだけということになります。
まとめると、今回のようにブランチが枝分かれしてなかったとき、元々のmainブランチのその先にhotfixブランチがあって、それをマージしただけのときはブランチのポインタが前に進むだけなのです。
このようなマージの方法を「Fast Foward」という呼び方をしています。
日本語にすると「早送りマージ」です。
マージの2種類目は「Auto Merge」という種類になります。
これが良くイメージされるような基本的なマージです。
これは何かというと、今状況としてmainブランチとfeatureブランチがあるとします。
それぞれmainブランチではmainブランチ専用の変更があって、featureブランチではfeatureブランチ専用の変更があります。
それぞれの変更内容が「23q1a」であったり「rf54h」というコミットファイルになっています。
では、このfeatureブランチの変更をmainブランチに取り込んでいきましょう。
取り込むために、「git merge feature」コマンドを実行します。
すると、新しいコミットファイルができます。
これはマージのコミットファイルで、「6847g」という新しいコミットファイルができています。
これは何が起こっているのかというと、mainブランチの内容をベースにして、その内容にfeatureブランチの変更分を取り込んだ内容をスナップショットとしてコミットに記録しています。
結果、新しいコミットファイル「6847g」という新しいコミットファイルができて、mainブランチが指しているポインタもそちらの方に移動しています。
この内容をまとめると、枝分かれてして開発していた場合、今回のようにmainとfeatureでそれぞれで枝分かれして開発していた場合、マージコミットという新しいコミットファイルが作られます。
そのことによって、変更履歴を統合するという作業がおこなわれています。
ちなみにこのマージコミットというコミットファイルは通常のコミットファイルと何が違うかというと、通常のコミットファイルはペアレント(自分の親)がひとつのコミットファイルの親しか持っていません。
ただマージコミットの場合は親を2つ持っている、ペアレントを2つ持っているというのが通常のコミットとは違っている点になります。
今回の場合ですと、「23q1a」というコミットファイルと「rg54h」というコミットファイルの2つのコミットファイルを親に持っているという点がマージコミットのユニークな点です。
ここまででマージの種類2つ目、オートマージという種類について説明してきました。
マージには後もう1種類あるのですが、そのもう1種類はコンフリクトと呼ばれています。
コンフリクトに関しては別途解説します。
実際にやってみよう
ではここまでの内容を実際に作業しながら確認してみましょう。
まずGitHubを開きます。
GitHubを開いたら自分のリポジトリに移動して、その中の「git_tutorial」リポジトリに移動して下さい。
ではまずFast Fowardのほうから確認してみましょう。
今状況として自分のmainブランチの内容をGitHubにpushした後だとします。
その後に誰か別の人がmainブランチに変更を加えました。
その変更分を自分のローカルのワークツリーの方に取り込む。
このようなシチュエーションだとします。
他の人がmainブランチの内容に変更を加えたというのを再現してみましょう。
「index.html」ファイルを開きます。
その中の右側にある鉛筆マーク「Edit this file」というのをクリックします。
ファイルの内容に変更を加えます。
今回は「<p>git merge</p>」と追記してみましょう。
追記したら保存します。
今回はコミットメッセージとして「git mergeを追記」としておきます。
ではコミットしましょう。
これでgit mergeというのが追記できました。
これで他の人がmainブランチの内容を変更したという状況が再現できたので、ターミナルを開いてその内容を自分のワークツリーの方に取り込んでいきます。
今回は「git pull」でその内容を取り込んでみましょう。
$ git pull origin main remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 685 bytes | 85.00 KiB/s, done. From github.com:piketa/git_tutorial * branch main -> FETCH_HEAD c16c8bf..f540e52 main -> origin/main Updating c16c8bf..f540e52 Fast-forward index.html | 1 + 1 file changed, 1 insertion(+)
「git pull」はフェッチとマージを同時におこなっているコマンドでした。
メッセージにはGitHubのgit_tutorialリポジトリの内容からフェッチ(取得)してきたと言うのが書かれています。
その取得してきた後に「Fast-forward」したよと言うことが表示されています。
では正しくマージできているのかを確認してみましょう。
まず「index.html」の内容を確認してみます。
$ cat index.html <h1>Gitチュートリアル</h1> <p>git status</p> <p>git diff</p> <p>git commit --amend</p> <p>git merge</p>
すると「git merge」というのが最後に書かれています。
このように内容の取り込みはうまくいっています。
ではFast-Forwardが本当にされているのかというのを「git log」コマンドで確認してみましょう。
$ git log --oneline f540e52 (HEAD -> main, origin/main) git mergeを追記 c16c8bf main.htmlファイルを新規作成 80dc6e9 Update home.html bd0605c Create home.html 61073d5 git commit --amendを追記 046df59 .gitignoreファイルを追加 a0fd302 git diffを追記 d7db51d git statusコマンドを追記 c9b5690 Initial commit
すると一番上に「git mergeを追記」というコミットメッセージが書かれたコミットになっています。
これは何が起きているのかというと、mainブランチがこの「f540e52」というコミットファイルを指していると言うことが分かります。
この「f540e52」というのはGitHub上で修正したコミットです。
そちらのコミットの方に今mainブランチのポインタが切り替わっている、つまりFast-Fowardされていると言うことが分かります。
では次にAutoMergeの方を見ていきましょう。
AutoMergeを確認するために、まず「git branch」でブランチの状況を確認するとfeatureブランチがあります。
$ git branch feature * main
AutoMergeを確認するために、featureブランチの方に修正を加えていきます。
まずブランチの切り替えを行いましょう。
$ git checkout feature Switched to branch 'feature'
これでfeatureブランチに切り替えができました。
ではfeatureブランチで変更を加えていきます。
テキストエディタで「feature.html」を開いて下さい。
今回は「<p>feature</p>」という行を1行追加してみたいと思います。
追加したら保存してターミナルに戻ります。
ターミナルに戻ったら、変更分をコミットしていきましょう。
$ git add feature.html $ git commit -m 'feartureを追記' [feature 677c930] feartureを追記 1 file changed, 1 insertion(+)
これでコミットができました。
ではここからこのfeatureブランチの内容をmainブランチの方に取り込んでいきます。
まずmainブランチの方に切り替えていきましょう。
$ git checkout main Switched to branch 'main'
featureブランチの内容を取り込みます。
$ git merge feature Merge made by the 'recursive' strategy. feature.html | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 feature.html
これがAutoMergeしたときにできるメッセージになります。
ではmainブランチの内容を確認して、本当にマージできたのか確認していきましょう。
まずlsコマンドでファイルの内容を確認します。
$ ls feature.html home.html index.html main.html secret.txt
するとfeature.htmlというファイルがあります。
feature.htmlファイルの内容を確認します。
$ cat feature.html <p>branch</p> <p>feature</p>
すると確かにfeatureと言う内容が追記されていることがわかります。
これでfeatureブランチの内容をmainブランチに取り込めたことが確認できました。
では次にgit logコマンドでマージコミットができているかを確認してみましょう。
$ git log --oneline ffbcc50 (HEAD -> main) Merge branch 'feature' 677c930 (feature) feartureを追記 f540e52 (origin/main) git mergeを追記 c16c8bf main.htmlファイルを新規作成 525da20 (origin/feature) feature.htmlファイルを新規追加 80dc6e9 Update home.html bd0605c Create home.html 61073d5 git commit --amendを追記 046df59 .gitignoreファイルを追加 a0fd302 git diffを追記 d7db51d git statusコマンドを追記 c9b5690 Initial commit
すると一番上に「Merge branch ‘feature’」というコミットメッセージのコミットができていることが確認できます。
このように枝分かれして開発してマージした場合は、このマージコミットと言われている(1行目)新しいコミットファイルが作成されて、ファイルの内容を統合することができています。
まとめ
マージには2種類あって、それぞれFastFowardというマージの種類と、AutoMergeというマージの種類でした。
ここで重要なことは、あくまで「git merge」というコマンドを使うと、他のブランチで開発していた内容を自分のワークツリーに取り込めると言うことでした。
参考図書
独学で挫折しそうになったら、オンラインプログラミングスクール