Squashing commits with Git’s rebase command is useful when you want to clean up your commit history. Here’s a step-by-step guide.
1. Check Which Commits to Squash
First, review the commit log to decide which commits you want to combine:
git log --oneline
Example:
a1b2c3d Fix typo
d4e5f6g Add feature X
h7i8j9k WIP: implement feature X
...
Suppose you want to squash Add feature X and WIP: implement feature X.
2. Start an Interactive Rebase
Run git rebase -i using the commit before the ones you want to squash as the base:
git rebase -i <base_commit_id>
In this case, if a1b2c3d is the commit before, you would run:
git rebase -i a1b2c3d
3. Edit the Commit List
Your editor will open with something like this:
pick d4e5f6g Add feature X
pick h7i8j9k WIP: implement feature X
Change the second pick to squash (or just s):
pick d4e5f6g Add feature X
squash h7i8j9k WIP: implement feature X
4. Edit the Commit Message
Next, Git will prompt you to combine commit messages:
# This is a combination of 2 commits.
# The first commit’s message is:
Add feature X
# The following commit message will also be included:
WIP: implement feature X
Clean it up so the final message is concise:
Add feature X
5. Finish the Rebase
Save and close the editor. Git will apply the rebase and squash the commits into one.
6. Troubleshooting
- If you hit conflicts: resolve them as usual, then run:
git add <fixed_files>
git rebase --continue
- If you want to cancel the rebase:
git rebase --abort
- After rewriting history: if the branch is pushed to a remote you will need to force-push the rewritten history:
git push --force-with-lease
(Prefer --force-with-lease over --force when collaborating.)
7. Squashing Including the Root Commit (--root)
By default git rebase -i <base> rebases starting after the specified base commit. If you want to include the very first (root) commit in an interactive rebase — for example to edit or squash the initial commit together with later commits — use the --root option:
git rebase -i --root
What this does
- Lists the root (initial) commit as the first entry in the interactive todo.
- Lets you
pick,reword,edit,squash, orfixupthe root commit just like any other commit. - Rewrites the root and all descendant commits (so every commit ID in the branch will change).
Common uses & examples
-
Squash all commits into a single initial commit
If you want a single commit that contains the whole history, keep the root as
pickand mark every other commit assquash(ors):
pick a1b2c3d Initial commit
squash d4e5f6g Add feature X
squash h7i8j9k WIP: implement feature X
...
After saving, Git will open the combined commit-message editor so you can craft the final message.
-
Edit or reword the root commit message
Change the first line to
reword(orr) to update the initial commit message during the rebase:
reword a1b2c3d Initial commit
pick d4e5f6g Add feature X
...
The rebase will stop and prompt you to edit the root commit message.
-
Amend the root content
Use
editon the root entry if you need to change the actual tree of the root commit (add/remove files). Rebase will stop at that commit; then you can modify files,git addthem, and rungit commit --amendbefore continuing the rebase:
# interactive todo:
edit a1b2c3d Initial commit
pick d4e5f6g Add feature X
...
# when rebase stops:
# make changes to the working tree
git add <files>
git commit --amend --no-edit # or edit message as needed
git rebase --continue
Caveats
- Rewriting the root rewrites the entire branch history. This is disruptive if the branch is shared — coordinate with collaborators or avoid rewriting published branches.
- After a
--rootrebase you must force-push to update any remote branch (git push --force-with-lease). -
git rebase -i --rootbehaves like a normal interactive rebase in terms of conflict resolution and aborting (git rebase --abort).
Summary
- Use
git rebase -i <base>to interactively squash commits after<base>. - Mark commits to squash with
squash(ors). - Edit the commit message when prompted.
- Complete the rebase and resolve conflicts with
git rebase --continue. - To include the initial/root commit in your rebase (so you can squash or edit it), run
git rebase -i --root. Be aware this rewrites the whole branch history and requires a force-push for published branches.
Git Rebaseで過去のコミットをSquashする方法
Gitのrebaseコマンドを使ってコミットをSquash(統合)すると、コミット履歴を整理したいときに便利です。以下に手順を説明します。
1. Squashするコミットを確認する
まず、コミットログを確認して、どのコミットをまとめるか決めます。
git log --oneline
例:
a1b2c3d タイポを修正
d4e5f6g 機能Xを追加
h7i8j9k WIP: 機能Xを実装
...
ここでは、機能Xを追加とWIP: 機能Xを実装をSquashするとします。
2. Interactive Rebaseを開始する
Squashしたいコミットの直前のコミットをベースとして、git rebase -iを実行します。
git rebase -i <base_commit_id>
この例で、a1b2c3dがその直前のコミットである場合は、次のように実行します。
git rebase -i a1b2c3d
3. コミット一覧を編集する
エディタが開き、次のような内容が表示されます。
pick d4e5f6g 機能Xを追加
pick h7i8j9k WIP: 機能Xを実装
2つ目のpickをsquash(または単にs)に変更します。
pick d4e5f6g 機能Xを追加
squash h7i8j9k WIP: 機能Xを実装
4. コミットメッセージを編集する
次に、Gitからコミットメッセージを統合するよう求められます。
# これは2個のコミットを組み合わせたものです。
# 1つ目のコミットメッセージ:
機能Xを追加
# 以下のコミットメッセージも含まれます:
WIP: 機能Xを実装
最終的なメッセージが簡潔になるよう整理します。
機能Xを追加
5. Rebaseを完了する
保存してエディタを閉じます。GitがRebaseを適用し、コミットを1つにSquashします。
6. トラブルシューティング
- コンフリクトが発生した場合:通常どおりコンフリクトを解消してから、次を実行します。
git add <fixed_files>
git rebase --continue
- Rebaseをキャンセルしたい場合:
git rebase --abort
- 履歴を書き換えた後:ブランチをすでにリモートへPushしている場合は、書き換えた履歴をForce Pushする必要があります。
git push --force-with-lease
(共同作業をしている場合は、--forceより--force-with-leaseを使用することを推奨します。)
7. ルートコミットを含めてSquashする(--root)
デフォルトでは、git rebase -i <base>は指定したベースコミットの次のコミットからRebaseを行います。最初のコミット(ルートコミット)もInteractive Rebaseの対象に含めたい場合(たとえば、初回コミットを編集したり、後続のコミットとSquashしたりする場合)は、--rootオプションを使用します。
git rebase -i --root
このコマンドの動作
- ルート(初回)コミットがInteractive Rebaseのtodoリストの最初の項目として表示されます。
- 他のコミットと同様に、ルートコミットに対して
pick、reword、edit、squash、fixupを指定できます。 - ルートコミットと、それ以降のすべてのコミットが書き換えられます(そのため、ブランチ内のすべてのコミットIDが変更されます)。
一般的な用途と例
-
すべてのコミットを1つの初回コミットにSquashする
履歴全体を含む1つのコミットにしたい場合は、ルートコミットを
pickのままにして、それ以外のすべてのコミットをsquash(またはs)に変更します。
pick a1b2c3d 初回コミット
squash d4e5f6g 機能Xを追加
squash h7i8j9k WIP: 機能Xを実装
...
保存すると、Gitが統合後のコミットメッセージを編集するためのエディタを開くので、最終的なメッセージを作成できます。
-
ルートコミットのメッセージを編集・変更する
Rebase中に初回コミットのメッセージを変更するには、最初の行を
reword(またはr)に変更します。
reword a1b2c3d 初回コミット
pick d4e5f6g 機能Xを追加
...
Rebaseが一時停止し、ルートコミットのメッセージを編集するよう求められます。
-
ルートコミットの内容を修正する
ルートコミットの実際のツリー(ファイルの追加・削除)を変更する必要がある場合は、ルートのエントリに
editを指定します。Rebaseはそのコミットで一時停止します。その後、ファイルを変更してgit addし、git commit --amendを実行してからRebaseを続行できます。
# Interactive Rebaseのtodo:
edit a1b2c3d 初回コミット
pick d4e5f6g 機能Xを追加
...
# Rebaseが停止したら:
# ワーキングツリーに変更を加える
git add <files>
git commit --amend --no-edit # 必要に応じてメッセージも編集
git rebase --continue
注意点
- ルートコミットを書き換えると、ブランチの履歴全体が書き換えられます。共有ブランチで行うと大きな影響があるため、共同作業者と調整するか、公開済みブランチの書き換えは避けてください。
-
--rootを使ってRebaseした後、リモートブランチを更新するにはForce Pushが必要です(git push --force-with-lease)。 -
git rebase -i --rootでも、コンフリクトの解消や中止(git rebase --abort)については通常のInteractive Rebaseと同様に動作します。
まとめ
-
git rebase -i <base>を使用すると、<base>より後のコミットを対話形式でSquashできます。 - Squashするコミットを
squash(またはs)に変更します。 - プロンプトが表示されたらコミットメッセージを編集します。
- Rebaseを完了し、コンフリクトが発生した場合は
git rebase --continueで続行します。 - 初回/ルートコミットをRebaseの対象に含めてSquashや編集を行うには、
git rebase -i --rootを実行します。この操作ではブランチの履歴全体が書き換えられ、公開済みブランチではForce Pushが必要になる点に注意してください。
Top comments (0)