GItで変更を統合するときに履歴を整えられるリベース(rebase)の使い方

Git

GItで変更を統合するときに履歴を整えられるリベース(rebase)の使い方をまとめました。

リベース(rebase)

リベース(rebase)とは、変更を統合するときに履歴をきれいに整えることです。
rebaseは、親となるコミット=ベース(base)を再度(re)指定し直しているためです。

変更を取り込む方法はmergeがありますが、リベースも変更を取り込む方法の一つです。

git rebase ブランチ名

ブランチの基点となるコミットを別のコミットに移動ささます。
たとえば、masterブランチとreviewブランチがコミット1から枝分かれしていて、masterブランチはコミット2を、reviewブランチはコミット3をそれぞれ指しているとします。
そのとき、

git checkout review

でreviewブランチに移動します。
そして、

git rebase master

とするとコミット3の親コミットがコミット1からコミット2に変わります。
そしてコミット3の内容をコミット2に取り込み、新しいコミット4が生成されます。コミット4はコミット2の後の最新の変更履歴として生成されます。親コミットはコミット2なので枝分かれを解消しつつ統合できます。
Masterブランチをコミット2からコミット4に移すため、

git checkout master

でmaster ブランチに切り替えて、

git merge review

とすると、review と同じくコミット4を指し示します。

このmergeはfast forwardが起こっていてマージコミットを作成する必要がなく、特に何も取り込まずにブランチを移動しています。

git config —global merge.ff false

とするとfast forwardしないように設定できます。

リベースの流れ

  1. 移したい方のブランチに移動する
  2. 基にしたいブランチをリベースする
  3. 基にしたいブランチに移動する
  4. 移したブランチを指定してマージする

リベースでやってはいけないこと

ひとつは、GitHubにプッシュしたコミットをリベースすることです。
リベースするとコミットの履歴がGitHubの履歴と異なるため、プッシュできなくなります。
新しいコミットをして、その内容を修正するようにしましょう。

もうひとつは、git push -fの使用です。
-fはforceのことです。
強制的に今あるGitHubの内容を上書きしてgit pushできますが、Gitの履歴が完全に壊れます。

リベースとマージ

どちらを使うかは運用次第です。
マージは、
– コンフリクトの解決が簡単
– マージコミットが複数あると複雑になる

リベースは、
– 履歴をきれいに保つことができる
– コンフリクトの解決が少し手間
リベースのコンフリクトはコミットそれぞれに解消必要になるので少し手間が増えます。
よってマージは作業の履歴を残したい場合につかいましょう。
履歴をきれいにしたい時にリベースつかいます。

マージとリベースのコンフリクト違い

たとえば次のようなケースみてみます。
コミット1を親するコミット2とコミット3があるとします。両方とも同じ場所を編集します。コミット3を親とするコミット4でもまた同じ場所を編集してコミット5を作成します。
その場合、マージはコミット2とコミット5という最終的なコミットのみコンフリクトが発生します。
リベース場合は、各コミットごとにコンフリクトが発生します。

プッシュしていないローカルの変更はリベース
プッシュした場合マージ
という使い分けがおすすめです。
また変更履歴を残したいとき、コンフリクトしそうな時マージがおすすめです。

プルにはマージ型とリベース型があります。
通常のgit pullはマージ型です。 git fetchしてgit mergeします。

git pull リモート名 ブランチ名

マージコミット残るので、マージしたことを記録に残したい場合に使いましょう。

リベース型のプルを利用する

git pull —rebase リモート名 ブランチ名

git fetchしてgit rebaseします。
マージコミットが残らないため、GitHubの内容を取得したいだけなら- rebaseつけるほうがいいでしょう。
またプルを基本リベース型使いたいという場合設定変更すればかのうになります。

git config --global pull.rebase true

masterブランチでgit pullするだけなら

git config branch.master.rebase true

とします。
git pullでリベース型で統合されるようになります。

リベースで履歴を書き換える方法

GitHubにプッシュしていないコミットあることを前提に、コミットをきれいに整えてからプッシュしたい時は履歴を書き換えます。

直前のコミットをやり直す

git commit —amend

とします。リモートリポジトリにpushしたコミットはやり直してはいけません。

複数のコミットをやり直す場合

git rebase -i コミットID

git rebase -i HEAD~3

-iはinteractiveの略です。対話的リベース(interactive)といってやり取りしながら履歴を変更します。
HEAD~は一番目の親を指定します。HEADを基点にして数値分の親コミットまで指定します。
たとえばHEAD~3など~数字を指定するとその数字の数だけ表示されます。
また、HEAD^(キャレット)と指定すると、マージした場合の指定した順番の親を指定します。
たとえばHEAD^2なら2番目の親を指定することができます。

そして、ターミナルではやり直したいcommitをeditに変更します。

pick コミットID ファイル追加

という部分を修正したい場合、

edit コミットID ファイル追加とREADME修正

とします。

コミットの内容を修正したい場合

git commit --amend

とします。
修正せず次のコミットへ進み見たい場合(リベース完了)

git rebase --continue

とします。

git rebase -iコマンドの流れ

  1. git rebase -iコマンドで対話的リベースモードに入りコミットエディタに入ります。
  2. そして、修正したいコミットをeditにしてコミットエディタを終了します。
  3. editのコミットのところでコミットの適用が止まります。
  4. git commit –amendコマンドで修正します。
  5. git rebase –continueコマンドで次のコミットへ進みます。
  6. pickであればそのままコミット内容を適用してその次に進みます。
  7. HEADまできたら自動的に終了します。

コミットを並び替えたり入れ替えたりする方法

git rebase -iコマンドを使用します。
履歴はgit logと逆の「古い順に表示される」ので注意が必要です。順番にrebaseしていくので逆になります。
コミットエディタ上で不要なコミットを削除し、並び替えたいものをエディタ上で並び替えます。

コミットをまとめる

git rebase -iコマンドを使用します。
pick部分をsquash(ぺたんこにする)と指定すると、そのコミットを直前のコミットとまとめることができます。

コミットを分割する

  1. git rebase -iコマンドを使用します。
  2. 分割したいコミットのpickをeditに変更する
  3. git reset HEAD^(git reset はステージングしてない状況にまで戻すコマンド、HEAD^がeditにしているコミットを指し示します。)
  4. git add 1つ目のファイル
  5. git commit -m 'ファイルの分割1’
  6. git add 2つ目のファイル
  7. git commit -m 'ファイルの分割2’
  8. git rebase –continue

Git

Posted by devsakaso