SakuraWi - BLog

WEBエンジニア。聴いたお話をまとめておく倉庫的な。スタックストックスタック!

gitのコミット履歴を書き換えよう!wipコミットをまとめたり不必要なコミットを削除する方法


みなさんgit使いこなせていますか?

gitのcommitが積み上がるのはいいけど、うまく整理したい!
そんな時に便利なコマンドが git rebase -iです。


git rebase

rebaseコマンドは基本的にcommitを修正するためのコマンドと言ってもいいでしょう。

git rebase masterなんかはみなさんもよく使っているのでは?

今回紹介するのは、そんなrebaseのオプションの-iいわゆる--interactiveってやつです。

使い方のフロー

今回は、gitの履歴で、以下のようなシーンを想定しています。

  • 採用したくないcommitがある時
  • commitを統合したいとき
    • wipなどのcommitがあるとき

それでは早速使って行きましょう。

と、その前に全体を通しての使い方を先に書いておきます。

修正したいcommitが積まれているブランチで以下のコマンドを打ち込みます
git rebase -i HEAD~5
~5の部分は修正したいcommitが入る分だけのcommit履歴数が入る数字にしましょう。
最新の状態から3つ分以内を修正したい場合は HEAD~3です。

ここで注意点ですが、
必要以上のcommitをHEAD~に含めてしまうとgit pushした際に余分なものもpushしてしまいがちなので注意。

採用したくないcommitがある時

さて、採用したくないcommitがある時の使用フローを書きます。

状況はこんなかんじとします。

$ git log --oneline
dbc05cb third
0b88237 second
2a570af first

3つのcommitが積み上がっているとします。

2番目のcommitをなかったことにしましょう。

git rebase -i HEAD~2と打ち込みます。

pick 0b88237 second
pick dbc05cb third

# Rebase 2a570af..dbc05cb onto 2a570af (2 commands)
...

するとvimが起動し、このような画面になるはずです。

ここで、それぞれのcommitをどう処理するかを記述します。

pick はcommitとして採用
s は下のcommitと統合
1行削除するとcommitがなかったことになります(drop)

今回は2番目のcommitをなかったことにしたいので、1行削除して保存します。

vimの場合は保存はescを押してから:wqで保存して終了できます。

その後、logをみてみましょう。

git log --onelineを打って見ます。

$ git log --oneline
dc52c71 third
2a570af first

お見事!2番目のcommitであるsecondがない状態となりました。ヤッタネ。

この状態でpushするには、-fのオプションが必要となります。commitの書き換えを行なっているので、リモートのorigin/masterと差分ができてしまうのは仕方ありません。

git push -f origin <branch>でOKです。

統合したいcommitがある場合

さて、では次にwipのcommitなど、不必要だけど更新があるcommitを統合したい場合を書きます。

状態はやはりこの状態から。

$ git log --oneline
1fc4b87 second
0903db0 wip
2a570af first

wipのcommitがある状態なので、これを firstと、secondだけの状態にします。
もちろん、wipのcommitの更新分は反映されるようにします。

git rebase -i HEAD~2を実行します。

pick 0903db0 wip
pick 1fc4b87 second

# Rebase 2a570af..1fc4b87 onto 2a570af (2 commands)
...

vimが起動し、このような表示がされるはずです。

ここで、wipのcommitのpicksに変更します。

s 0903db0 wip
pick 1fc4b87 second

# Rebase 2a570af..1fc4b87 onto 2a570af (2 commands)
...

こんな感じです。

これで、保存してみましょう。

するとあら不思議、logをみると綺麗になっています。

と、思いきやできませんでした。

rebase -iでのsによる統合は、以前のcommitに統合されるようです。 firstのcommitは最初のcommitであるため、認識されずに失敗してしまったようです。

気を取り直して、作り直しました。

$ git log --oneline
0958e38 third
a7e62a8 wip
22d29bf second
2a570af first

この状態から、git rebase -i HEAD~3を実行。

pick 22d29bf second
pick a7e62a8 wip
pick 0958e38 third

このwipのcommit部分を

pick 22d29bf second
s a7e62a8 wip
pick 0958e38 third

sにしてあげて保存します。

すると、次のcommitメッセージ変更状態になります。

# This is a combination of 2 commits.
# This is the 1st commit message:

second

# This is the commit message #2:

wip

以上の内容をまとめたいcommitメッセージだけにします。

例えばこんな感じ。

second

不必要な部分は消しました。そして保存。

これでwipなどのcommitをその前のcommitと統合することができました!!

エラー

fatal: Needed a single revision
invalid upstream HEAD~3

このようなエラーがよくでます。
first commit の分は認識されないようです。

そりゃ、最初のcommitがないと起点がなくなるわけですので、そちらはいじることはできない、ということでしょう。

参考

こちらにより詳しい内容が書いています。

Git - 歴史の書き換え