電気ひつじ牧場

技術メモと日常のあれこれ

Gitでコミットを分割する

ハッシュがa6e0229のコミットは関係ない2ファイルを同時にコミットしており,これを1ファイルずつのコミットに分割したいとする.コミットログはこのようになっている.

* 6eba8e2 (HEAD -> master) add README.md
* a6e0229 add server
* 9f80a28 update

修正したいコミットの1つ前を指定してrebase -iする.

$ git rebase -i 9f80a28

エディタが開く

pick a6e0229 add server
pick 6eba8e2 add README.md

# Rebase 9f80a28..6eba8e2 onto 9f80a28 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
....(omitted)

変更したいコミットのハッシュがある行を次のように変更してエディタを終了させる.

- pick a6e0229 add server
+ edit a6e0229 add server

この時点でのステータスはこんな感じ.先ほどpickeditに変更したコミットまで実行されている状態になっている模様.ここから分割をしていく.

$ git status
interactive rebase in progress; onto 9f80a28
Last command done (1 command done):
   edit a6e0229 add server
Next command to do (1 remaining command):
   pick 6eba8e2 add README.md
  (use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'master' on '9f80a28'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working tree clean

まずリセットを行いHEADとブランチが指すコミットを巻き戻す.インデックスもそのコミットで書き戻された状態になる.ワーキングディレクトリはそのまま.

$ git reset HEAD^

次に意図した通りに適切な粒度でコミットを行う.単純な分割であれば最終的に分割前のコミットが終わった時と同じ状態になっている.

$ git add server.py
$ git commit -m "add server"
$ git add access.py
$ git commit -m "add access"

分割が終わればリベースを続行する.

$ git rebase --continue

最終的にコミットログはこのようになる.リベースで指定したコミットより後ろのコミットは全てハッシュが変わっている(分割に関与していないものも含めて)ため,すでにpushしている場合は気をつけるべき.

* a0b6c70 (HEAD -> master) add README.md
* aa5babd add access
* fdc480d add server
* 9f80a28 update