はじめに
過去のコミットに入れ忘れた変更を、後からそのコミットに足したくなることはありませんか?
これがもし直前のコミットであれば次の手順で済みます。
git add
git commit --amend
一方で、2つ以上前のコミットへ変更を追加する方法は少し手順が増えます。本記事では備忘録として、
「commit --fixup
と rebase --autosquash
」の組み合わせた方法を具体例つきで整理します。
注意: 公開ブランチや複数人で共有しているブランチの履歴を書き換えると、他の人の作業に影響します。どうしても必要な場合のみ行い、リモートへの反映は必ず
--force-with-lease
を使用してください。
やりたいこと(デモ)
4つ前のコミット「a5ba1ac bbb.txtの編集
」に、現在の未コミット変更を追加したいものとします。
コミット履歴の例
# コミット履歴を表示
$ git log --oneline -n 5
c853874 (HEAD -> master) ccc.txtの編集 # 最新のコミット
feb4f47 ccc.txtの新規作成
d26f8d2 .gitignoreの追加
a5ba1ac bbb.txtの編集 # ← このコミットに追加したい
f94e37b bbb.txtの新規作成
a5ba1ac
のコミット内容(bbb という文字列を3行追加)
現在の作業ツリーの変更(4つ前のコミットへ取り込みたい差分)
$ git status
On branch master
Your branch is ahead of 'origin/master' by 5 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: bbb.txt # ← 変更ファイル
no changes added to commit (use "git add" and/or "git commit -a")
方法: commit --fixup
と rebase --autosquash
を使う
--fixup=<コミットID>
で「対象コミットを直すための一時コミット」を作り、rebase -i --autosquash
でその一時コミットを目的のコミットへ自動で結合します。
手順
# 1) 直したい変更をステージ
git add <変更されたファイル名>
# 2) 直したい過去コミットへ fixup コミットを作成
git commit --fixup=<コミットID>
# 3) 自動で並び替え&結合(対象コミットの親を指定)
git rebase -i --autosquash <コミットID>^
# 4) リモートへ反映(安全な強制上書き)
git push --force-with-lease
補足:
--force-with-lease
は「自分が最後に把握していたリモート先端」と一致しない場合は拒否します。リモートの履歴保護に役立つオプションです。
デモの具体例
# 1) 直したい変更をステージ
git add bbb.txt
# 2) 直したい過去コミットへ fixup コミットを作る
git commit --fixup=a5ba1ac
# 3) 自動で並び替え&結合
git rebase -i --autosquash a5ba1ac^
# 4) リモートへ反映
git push --force-with-lease
2)を実行すると、fixup!
というプレフィックスのついたコミットが一時的に作成されます。
$ git log --oneline -n 6
622ba3f (HEAD -> master) fixup! bbb.txtの編集 # 一時コミット
c853874 ccc.txtの編集
feb4f47 ccc.txtの新規作成
d26f8d2 .gitignoreの追加
a5ba1ac bbb.txtの編集
f94e37b bbb.txtの新規作成
3)の実行時、エディタが開きます(例は Vim)。内容はすでに fixup
指示が入った状態なので、基本はそのまま保存して閉じます。
(:wqまたは:x とエンターキー)
1 pick a5ba1ac bbb.txtの編集
2 fixup 622ba3f fixup! bbb.txtの編集
3 pick d26f8d2 .gitignoreの追加
4 pick feb4f47 ccc.txtの新規作成
5 pick c853874 ccc.txtの編集
6
7 # Rebase f94e37b..622ba3f onto f94e37b (5 commands)
8 # ...(以下ヘルプ)
その後のコミット履歴は次のように書き換わり、fixup!
の一時コミットは消え、目的の4つ前のコミットに変更が取り込まれます(コミットIDは新しくなります)。
$ git log --oneline -n 5
1e215bb (HEAD -> master) ccc.txtの編集
896b39e ccc.txtの新規作成
c9b0746 .gitignoreの追加
3b3a76f bbb.txtの編集 # ← コミットIDが更新
f94e37b bbb.txtの新規作成
更新された3b3a76f
のコミット差分を確認すると、加えたかった "hoge" の行が含まれていることが分かります。
おわりに
2つ以上前のコミットへ変更を追加したいときは、commit --fixup
と rebase --autosquash
の組み合わせがシンプルな方法なのかなと思います。
履歴を書き換える操作であることは念頭に置きつつ、必要な場面だけ最小限に使いましょう。
どこかのタイミングで思い出す助けになれば嬉しいです。