昨日は、リベースの基本的な使い方まで。
今日は、さらに強力なコミットの細かい指定と、リベース中のコントロールについて。
コミットの細かい指定
リベースの基本的な考え方として、リベースとはパッチを順番に当てていく操作だということを書いたけど、なんと、そのパッチの当て方を細かくコントロールすることも出来る。
これによって、各コミットの内容自体を改変することも出来てしまう。
実行方法
コミットの細かい指定を行うには、--interactive
オプション(あるいは省略形の-i
)を使う。
$ git rebase -i (newbaseの指定など)
このコマンドを実行するとエディタが立ち上がり、例えば次のような画面が表示される。
pick bbbbbbb 機能Aを実装。 pick ccccccc 機能Bを実装。 pick ddddddd バグを修正。 pick eeeeeee 機能Cを実装。 pick fffffff 開発ブランチをマージ。 # Rebase aaaaaaa..fffffff onto 1111111 ( 5 TODO item(s)) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
ここには、これからリベースで当てていく予定のパッチのリストと、このリストの編集方法に関するコメントが書かれている。
このリストを編集することで、コミットの細かい指定を行っていくことが出来る。
リストの編集
リストの各行には、そのコミットをどう扱うのかを表したコマンドと、コミットのハッシュ値(の先頭部分)、それにコミットメッセージが書かれている。
このコマンドをデフォルトのpick
から変えることで、そのコミットの扱いが変わってくる。
- pick
そのコミットをそのまま使う。(デフォルト) - reword
そのコミットを使うが、コミットメッセージの修正を行う。 - edit
そのコミットを使うが、コミットの修正を行うためにリベースを一時停止する。 - squash
そのコミットでの変更内容を直前のコミットに入れるようにし、コミットを1つにする。
(コミットメッセージの変更も行う) - fixup
そのコミットでの変更内容を直前のコミットに入れるようにし、コミットを1つにする。
(コミットメッセージの変更は行わず、そのコミットのコミットメッセージは捨てられる) - exec
execに続く内容をシェルで実行する。
(コミットのリストの間に追加する)
なお、このリストの順番を入れ替えると、パッチを当てる順番が変更される。
さらに、リストから一行削除すると、そのコミットは使われなくなる。
コミット内容の修正
過去のコミットに遡ってそのコミットの変更内容を修正したいという場合がある。
その場合、上記のedit
コマンドを使う。
edit
を指定すると、まずそのコミットが適用され(ここ重要)、コミットが終わった状態でリベースが一時停止される。
その状態で追加の変更などを行い、git commit --amend
を行うことで、そのコミットの内容を修正することが出来る。
なお、git commit --amend
でなく単にgit commit
を行うと、新たなコミットが追加されるので、注意。
(逆に言えば、あるコミットとあるコミットの間に新しいコミットを挟みたい場合には、この方法をとることになる)
コミット内容が修正し終わったら、git rebase --continue
とすることで、リベースが再開される。
コミットの分割
過去のコミットを2つ以上のコミットに分割したいというときが、たまにある。
例えば、機能Bを実装したときに機能Aのバグに気がついて一緒に直したけれど、変更理由が明確になるように、この変更だけを切り出して一つのコミットにしたい場合とか。
そういった場合、まずはコミットのリストを編集するときに、分割したいコミットに対してedit
を指定する。
そして、分割したい変更内容がコミットされ、リベースが一時停止している状態で、次のようにする。
$ git reset HEAD^
こうすると、直前にされたコミットが取り消され、その変更内容だけがワーキングツリーに残っている状態になる。
そこで、適切にgit add
、git commit
をしてやることで、コミットを分割することが出来る。
リベース中のコントロール
リベースを行っていると、変更の衝突(コンフリクト)が起きたり、あるいはedit
コマンドを使ったことにより、リベースが一時停止されることがある。
その場合、変更の衝突を解決したり、コミット内容の修正が終わったら、リベースを再開させないといけない。
リベースを再開させるには、次のコマンドを実行する。
$ git rebase --continue
こうすると、リベースが再開され、次のパッチを当てる操作が行われる。
あるいは、場合によっては、やっぱり途中でリベースを止めたいとなることもある。
その場合、次のコマンドを実行する。
$ git rebase --abort
こうすると、途中まで進んでいたリベースも全て巻き戻されて、リベースを行う直前の状態に戻る。
なお、リベースが終わってから、やっぱりリベースしない方がよかった、となることもある。
その場合には、次のコマンドを使う。
$ git reset --hard ORIG_HEAD
これで何もかもが元通り!
今日はここまで!