Git: コミット履歴の順番を変えたい
要望
Gitで管理する前に作成していた古いソースコードを、Gitでの管理を始めたバージョンよりも前のコミット履歴に挿入したい。
あたかも、古いソースコードも初めからGitで管理していたかのように見せたい。
解決策
git rebase -i
を使ってコミット履歴の順番を入れ替えます。
手順
1. 古いソースコードをコミットする
まず、古いソースコードをそのままコミットします。
履歴は下記のようになります。
$ git log --oneline c2c2028 過去に挿入したいコミット 38ecb35 第5回目の変更 b88bc77 第4回目の変更 224be5e 第3回目の変更 5a15e86 第2回目の変更 a9c1f0a 第1回目の変更 2809352 test.txtを追加 2f3f471 最初のコミット
その上で、「過去に挿入したいコミット」を「test.txtを追加」の後に挿入します。
2. 「git rebase -i」を実行する
挿入する場所の直前のコミットのIDを指定してgit rebase -i
を実行します。
$ git rebase -i 2809352
画面がviに切り替わります。
yy
, dd
, P
などのコマンドを使って、行をコピペしたり削除したりします。
yy
: 一行をコピーdd
: 一行を削除P
(大文字): コピーしたものを貼り付ける。
行の場合はカーソルの上に挿入される。
(参考: viコマンド(vimコマンド)一覧(検索・置換))
変更前
pick a9c1f0a 第1回目の変更 pick 5a15e86 第2回目の変更 pick 224be5e 第3回目の変更 pick b88bc77 第4回目の変更 pick 38ecb35 第5回目の変更 pick c2c2028 過去に挿入したいコミット (以下略)
変更後
pick c2c2028 過去に挿入したいコミット pick a9c1f0a 第1回目の変更 pick 5a15e86 第2回目の変更 pick 224be5e 第3回目の変更 pick b88bc77 第4回目の変更 pick 38ecb35 第5回目の変更 (以下略)
3. 衝突を解決する
viを終了すると、下記のようにエラーを告げられます。
過去に挿入したいコミット
が割り込んだことで、その直前のtest.txtを追加
とのマージに衝突が起こりました。
これを手動で解決しなければなりません。
(rebase 実行後の画面)
$ git rebase -i 2809352 error: could not apply c2c2028... 過去に挿入したいコミット When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort". Could not apply c2c2028470e3c67fd00fe515e0376ed30026d174... 過去に挿入したいコミ ット $
エディタで衝突箇所を確認します。
エラーメッセージにerror: could not apply c2c2028... 過去に挿入したいコミット
とあるように、今回は過去に挿入したいコミット
の時点でのソースコードの状態を整えます。
解決前
<<<<<<< HEAD ======= 過去に挿入したい文章 >>>>>>> c2c2028... 過去に挿入したいコミット
解決後
過去に挿入したい文章
4. コミットメッセージを変更する
衝突を解決したら、下記のようにrebaseを続けます。
$ git add test.txt $ git rebase --continue
今度は過去に挿入したいコミット
のコミットメッセージを変更するためにviに切り替わります。
が、変更する必要はないので:q
で終了します。
(コミットメッセージ変更の画面)
過去に挿入したいコミット # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # rebase in progress; onto 2809352 # You are currently rebasing branch 'master' on '2809352'. # # Changes to be committed: # modified: test.txt #
5. 衝突を解決する (その2)
今度は、過去に挿入したいコミット
とその直後の第1回目の変更
とのマージに衝突が起こりました。
これを解決します。
(rebase --continue 実行後の画面)
$ git rebase --continue [detached HEAD e3057de] 過去に挿入したいコミット 1 file changed, 1 insertion(+) error: could not apply a9c1f0a... 第1回目の変更 When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort". Could not apply a9c1f0aa41a5ea1b5a495ee6bb94edfad4f9d7ee... 第1回目の変更
今回は第1回目の変更
の時点でのソースコードの状態を整えます。
解決前
<<<<<<< HEAD 過去に挿入したい文章 ======= 1 >>>>>>> a9c1f0a... 第1回目の変更
解決後
1
6. コミットメッセージを変更する (その2)
衝突を解決したら、rebaseを続けます。
$ git add test.txt $ git rebase --continue
今回もコミットメッセージを変更する必要はありません。
:q
でエディタを終了します。
(コミットメッセージ変更の画面)
第1回目の変更 # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # rebase in progress; onto 2809352 # You are currently rebasing branch 'master' on '2809352'. # # Changes to be committed: # modified: test.txt #
7. rebase 完了
この後も各コミット間で衝突がないか検査されますが、途中で止まらずにrebaseが完了するはずです。
$ git rebase --continue [detached HEAD 4300ca7] 第1回目の変更 1 file changed, 1 insertion(+), 1 deletion(-) Successfully rebased and updated refs/heads/master.
確認すると、順番が入れ替わっています。
また、IDが新たに割り振られています。
$ git log --oneline 29b1ca1 第5回目の変更 bceed4b 第4回目の変更 fd04728 第3回目の変更 2ab05f1 第2回目の変更 4300ca7 第1回目の変更 e3057de 過去に挿入したいコミット 2809352 test.txtを追加 2f3f471 最初のコミット
注意点
- すでにリモートにプッシュしているコミットの履歴は変更するべきではないでしょう。
- いろいろ試したのですが、最初のコミットよりも前に挿入することはできないようです。
2番目に古い位置にしか挿入できない、ということです。