はじめに
こんにちわ!
マイ ニフティチームの寺島です。
普段はスマートフォン向けのアプリケーション開発に携わっています。
ブログ運営チームのメンバーでもあります!
機能開発やバグ修正を進めていると、途中で「typo修正」「ログ出力追加」「ちょっとリファクタ」など、小さなコミットが積み重なることがありますよね。そのままプルリクエストを出すと、コミット履歴が細かすぎてレビューしづらくなったり、プロジェクト全体の履歴がノイズが多くなってしまったりします。
そんなときに役立つのが、Gitのrebase -i
コマンドを使った「コミットの整理」です。
特に複数のコミットを一つにまとめる(squashする)方法は、プルリクエストを出す前の準備として非常に有効です。
今回、実際に手を動かしながら、git rebase -i
を使って複数コミットを一つにまとめる手順を解説します。
ハンズオン用のリポジトリを作成する
今回のハンズオンで使用するダミーのリポジトリを作成します。
適当なディレクトリで以下のコマンドを順に実行してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 作業用ディレクトリを作成 mkdir git-squash-demo cd git-squash-demo # Gitリポジトリを初期化 git init # ダミーファイルを作成し、最初のコミット echo "Hello, Git Squash" > README.md git add README.md git commit -m "feat: add initial README file" # 状態確認 git log --oneline |
git log --oneline
を実行すると、最初のコミットが表示されるはずです。
次に、まとめる対象となる複数のコミットを作成していきます。
いくつかの変更を加え、それぞれ順にコミットしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 2つ目のコミットを作成 echo "This is the second line." >> README.md git add README.md git commit -m "chore: add second line" # 3つ目のコミットを作成 echo "This is the third line for refactor." >> README.md git add README.md git commit -m "refactor: improve wording" # 4つ目のコミットを作成 echo "Add final sentence." >> README.md git add README.md git commit -m "feat: add final sentence" # 現在の履歴を確認 git log --oneline |
git log --oneline
を実行すると、以下のように4つのコミットが積み重なっていることが確認できるはずです。(ハッシュ値は環境によって異なります)
1 2 3 4 |
<最新のハッシュ> feat: add final sentence <3つ目のハッシュ> refactor: improve wording <2つ目のハッシュ> chore: add second line <最初のハッシュ> feat: add initial README file |
これで準備は完了です!
最新の3つのコミット(”chore: add second line”、”refactor: improve wording”、”feat: add final sentence”)を一つにまとめてみましょう。
rebase -i を開始する
git rebase -i
コマンドは、「どのコミットまで」を対象にするかを指定して実行します。
指定したコミットより新しいコミットがインタラクティブなrebaseの対象となります。
今回は最新の3つのコミットを対象にしたいので、「最初のコミット(feat: add initial README file
)」の次からを対象にします。
最新のコミットから数えて対象のコミットが何番目か分かっている場合は、HEAD~N
という形式で指定できます。
今回は最新の3つのコミットを対象にするので、HEAD~3
を指定します。
これは「HEADから3つ遡ったコミットまで」を意味し、結果的に最新の3つのコミットが操作対象になります。
1 2 |
# 最新から3つのコミットを対象にインタラクティブrebaseを開始 git rebase -i HEAD~3 |
このコマンドを実行すると、エディタが立ち上がります(使用するエディタはGitの設定によります)。エディタには、対象となるコミットが古い順に表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
pick <2つ目のハッシュ> chore: add second line pick <3つ目のハッシュ> refactor: improve wording pick <最新のハッシュ> feat: add final sentence # Rebase <ハッシュ値>..<別のハッシュ値> onto <別のハッシュ値> (<コミット数> ahead) # # 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 # f, fixup [-C | -c] <commit> = like "squash" but keep only the previous # commit's log message, unless -C is used, in which case # keep only this commit's message; -c is same as -C but # opens the editor # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # create a merge commit using the original merge commit's # message (or the oneline, if no original merge commit was # specified); use -c <commit> to reword the commit message # u, update-ref <ref> = track a placeholder for the <ref> to be updated # to this position in the new commits. The <ref> is # updated at the end of the rebase # # 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. # |
エディタでコミットを整理する
エディタには、各コミットの左側にコマンドが記述されています。デフォルトはpick
になっており、そのコミットを採用するという意味です。
複数のコミットを一つにまとめたい場合は、まとめたいコミットの行のpick
をsquash
またはs
に変更します。 squash
はそのコミットを直前のコミットにまとめます。s
はsquash
の短縮形です。
今回は最新の3つのコミット(”chore: add second line”, “refactor: improve wording”, “feat: add final sentence”)を、一番古いコミット(”chore: add second line”)にまとめたいです。
2番目と3番目のコミットのpick
をs
に変更します。
エディタの内容を以下のように修正してください。
1 2 3 4 5 6 |
pick <2つ目のハッシュ> chore: add second line s <3つ目のハッシュ> refactor: improve wording <- ここを s に変更 s <最新のハッシュ> feat: add final sentence <- ここを s に変更 # コメント行はそのまま、または削除してOK ... |
※一番上の行(今回まとめたいコミット群の中で一番古いもの)はpick
のままにしておきます。
これがまとめたコミットの「土台」になります。
修正したら、エディタを保存して閉じます。
コミットメッセージを編集する
エディタを閉じると、Gitがrebase処理を実行し、まとめたコミットの新しいコミットメッセージを作成するためのエディタが再度立ち上がります。
このエディタには、squash
に指定した各コミットのメッセージが自動的に結合された状態で表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# This is a combination of 3 commits. # This is the 1st commit message: chore: add second line # This is the 2nd commit message: refactor: improve wording # This is the 3rd commit message: feat: add final sentence # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch main # Changes to be committed: # modified: README.md # |
この結合されたメッセージを編集し、まとめたコミットとして適切なコミットメッセージに書き換えます。
不要な行(特に#
で始まるコメント行や、元のコミットメッセージのヘッダー部分)は削除し、最終的なコミットメッセージだけを残しましょう。
例:
1 2 |
feat: Add second, third, and final lines to README |
メッセージを編集したら、エディタを保存して閉じます。
結果を確認する
エディタを閉じると、rebase処理が完了します。
念のため、git log --oneline
コマンドでコミット履歴を確認してみましょう。
1 |
git log --oneline |
最新の3つのコミットが一つにまとまり、先ほど編集した新しいコミットメッセージになっていることが確認できるはずです。元の3つのコミットは履歴から消えています。
1 2 |
<新しいコミットのハッシュ> feat: Add second, third, and final lines to README <最初のハッシュ> feat: add initial README file |
これで、複数のコミットを一つにまとめることができました!
おわりに
git rebase -i
のsquash
オプションを使うことで、開発途中で増えた細かなコミットを一つにまとめることができます。これは、コミット履歴を綺麗に保ち、プルリクエストのレビューを効率化するために非常に役立ちます。
git rebase -i <対象の範囲>
でインタラクティブrebaseを開始する。- エディタで、まとめたいコミットの
pick
をs
(squash) に変更する。 - 一番上のコミット(まとめる先)は
pick
のままにする。 - 次に表示されるエディタで、まとめたコミットの新しいメッセージを作成する。
適切に使えば、Gitワークフローがより洗練されるはずです。ぜひ試してみてください!