はじめに
Gitはプロジェクト管理システムの一種ですが、私は今までSVNを使ってきました。しかし、前職から転職したのをきっかけに、触れたことがなかったGitを使い始めました。
開発作業で他人の変更を自分の環境に取り込みたいとき、Gitではどうすれば…?調べた結果、git mergeというものがあると分かりました。しかしこれを使っている内に、あることに気づきました。マージしただけなのにコミット履歴に何かいる。それはマージコミットでした。
変更内容以外のコミット履歴が増え続けるのは、作業履歴を振り返る際に分かりづらくなるため、避けたい…。チームの先輩に相談したところ、rebaseを使っていることを知りました。(初めからマージ方法を伺っていればと反省しましたが、その点についてはご容赦ください。)
本記事では「git merge」と「git rebase」の違いについて備忘録としてまとめました。
git merge
現プロジェクトではブランチを以下のように運用しています。(ローカルリポジトリ)
masterブランチ
developブランチ
┗feature/Aブランチ
feature/Bブランチ
私がfeature/Aブランチを作成して開発作業をしている最中に、feature/Bブランチがdevlopにマージされたとします。このとき私はローカルリポジトリで以下のように操作していました。
// 1. リスト1最新のdevelopブランチをローカルにプルする
$ git checkout develop
$ git origin develop pull
// 2. feature/Aブランチをdevelopブランチにマージする
$ git checkout feature/A
$ git merge develop
// 3. origin/feature/Aブランチにプッシュする
$ git push
リポジトリの履歴を簡単な図にすると、このようになります。
git rebase
一方でgit rebaseでは以下の操作をします。
// 1. リスト1最新のdevelopブランチをローカルにプルする
$ git checkout develop
$ git origin develop pull
// 2. feature/Aブランチをdevelopブランチにマージする
$ git checkout feature/A
$ git rebase develop
// 3. origin/feature/Aブランチにプッシュする
$ git push -f origin/feature/A
mergeとの分かりやすい違いは、developの変更にマージした時にrebaseではマージコミットが作られないことです。git rebaseを行うとfeature/Aブランチのコミットがカットされ、developブランチの先頭に再作成(コピー)されます。そのため履歴を一本にすることができ、変更履歴が見やすくなります。
ただし、以下の注意が必要になります。
- git pushは強制プッシュ(git push -f)でないとリモートに反映できない。
- rebaseは必ず自分だけが使うブランチでのみ使用する。(複数人が使うブランチでrebaseをすると整合性がとれなくなるため。)
こんなときどうする
万が一誤ってrebaseをしてしまった場合は以下のコマンドを実行します。
$ git reflog
// 履歴から戻したいポイントのハッシュ番号を確認
$ git reset --hard HEAD@{番号}
$ git push -f origin ブランチ名
また、コンフリクトが発生した場合は競合しているファイルを修正して再度コミットした後に以下のコマンドを実行してrebaseを続けます。
// コンフリクトを解消してrebaseを続行する
$ git rebase --continue
おまけ
GitのクライアントツールであるSourceTree(Mac版)ではなぜかデフォルトで強制プッシュができないようになっています。しかし、設定変更等の手順を踏めばできるようになります。詳しい手順は以下の記事を参考にしました。
"Mac版SourceTreeでForce Push (強制プッシュ)を行えるように設定する"
以上です。