gitでコミットの順序を入れ替える 2023


2023年 05月 30日

3行の要約

以下のコマンドで,直前の2コミットを入れ替えできます.
GIT_SEQUENCE_EDITOR='sed -i "1{h;d};2G"' git rebase -i HEAD~2
入れ替えは,移動したいコミットのドラッグ&ドロップが便利です(GitHub DesktopのHistory画面).

はじめに

「コミット 順番」で検索をすると,検索上位に2010年に投稿されたTIMの技術ブログ記事が出てきます.

2023年3月の集計でも,全体で9番目にPV数が多い人気記事です.(技術者ブログの月間集計)
2010年の記事内容が2023年になっても役に立つのは嬉しいことですが,この十年でgitも発展を遂げました.

そこで,この記事では「gitでコミットの順序を入れ替える 2023」として,2010年の記事とは異なるコミット順序の入れ替え方法を紹介します.今でも2010年の方法が一般的ですが,より簡単に入れ替えができます.
GitHub DesktopとGit Bashでのやり方を紹介します.

問題

2つのファイル「01.txt」と「aa.txt」を順番にコミットします.

$ git add 01.txt
$ git commit -m 'Create 01.txt'
$ git add aa.txt
$ git commit -m 'Create aa.txt'

次に,同様の操作で「02.txt」をコミットします.コミットログは,以下になります.

$ git add 02.txt
$ git commit -m 'Create 02.txt'

$ git log --oneline --no-decorate
2644dce Create 02.txt
4235344 Create aa.txt
99473a1 Create 01.txt
d539dca Initial commit

この操作をGitHub Desktopで実行すると,以下の画面になります.

01.txtと02.txtのコミットは,連続した順番の方が美しいですよね.
このコミットログの順序を入れ替えて,綺麗な形に書き換えましょう.

解決方法(GitHub Desktop編)

GitHub Desktopでの操作は非常に簡単です.
History画面で,移動したいコミットをドラッグ&ドロップで希望の位置に持っていくだけです.
このとき,ドラッグしたコミットはコミットの間に移動させる点に注意して下さい.
別のコミットの上に移動させると,2つのコミットを1つにまとめるsquash操作になります.
「Squash 2 Commits」というコミットメッセージを求めるポップアップが出るため,右上の×ボタンを押せばsquash操作は回避できます.
コンフリクトが発生しなければ,これだけでコミットの順序入れ替え操作が完了します.

解決方法(Bash編)

GitHub Desktop編と同様に,「Create 01.txt」コミットを「Create aa.txt」コミットの後に移動させます.
Bashの場合,以下のコマンドでコミットの順序を入れ替えできます.

$ GIT_SEQUENCE_EDITOR='sed -i "1{h;d};2G"' git rebase -i HEAD~3

git rebase -i HEAD~3は,直近の3コミットをinteractiveモードで編集する一般的なコマンドです.
このコマンドのみ実行するとテキストエディタが起動するため,そのエディタを操作してコミットを入れ替える必要があります.
このとき,git logとは表示の順序が逆になっている点に注意が必要です.
コミットの書かれた1-3行目の順序を入れ替えるとコミットの順序が入れ替わります.


GIT_SEQUENCE_EDITOR='sed -i "1{h;d};2G"'がコマンドの肝になります.
このコマンドは,git rebase -iによって起動するエディタとしてsed(Stream EDitor)を指定しています.
そして,sedでテキストを入れ替えることで,コミットの順序を入れ替えます.
利用したsedコマンドは,以下になります.

  • -i ファイルを直接編集
  • h  ホールド・スペースとパターン・スペースの内容を交換
  • d  パターン・スペースを削除して次のサイクルを開始
  • G パターン・スペースにホールド・スペースの内容を追加

テキストの1行目の内容を2行目に挿入することで,コミットの順序を入れ替えています.
以下の数値の並び替え操作を見ると,sedの理解が深まるかもしれません.

$ seq 5
1
2
3
4
5

$ seq 5 | sed '1{h;d};2G'
2
1
3
4
5

$ seq 5 | sed '3{h;d};5G'
1
2
4
5
3

$ seq 5 | sed '3{h;d};1G'
1

2
4
5

この操作では,指定行を上に移動できません.
コミットの順序入れ替え操作では,古いコミットを新しい位置に移動させるように記述してください.

感想・終わりに

偉大な先輩であるkanaさんと同じ題目で記事を書いてみました.
コミットの順序入れ替えですが,GitHub Desktopを使うのが一番便利だと思います.
Bashでの操作は応用力は高いですが,実際の出番は少ない気がしています.
ただ,GIT_SEQUENCE_EDITORの指定を変えたりsedの操作を変更することで,大規模に機械的にコミットの順序入れ替えができます.そういう操作ができると知っていることは,大事だと思います.