はじめに

チーム開発でプルリクエストを作成する際、「コミット履歴が散らかっていて見づらい」と感じたことはありませんか。作業中に何度も小さなコミットを積み重ねた結果、「typo修正」「さらに修正」といったコミットが並んでしまうことは珍しくありません。

git rebaseを使えば、このような散らばったコミット履歴を整理し、論理的でわかりやすい履歴に書き換えることができます。本記事では、Git rebaseの基本概念からインタラクティブリベースによるsquash・fixup・rewordの活用法、そして公開ブランチへのリベースにおける注意点までを体系的に解説します。

この記事を読み終えると、以下のことができるようになります。

  • git rebaseの基本的な仕組みと使い方を理解できる
  • マージとリベースの違いを明確に説明できる
  • インタラクティブリベースでコミットを統合(squash)・修正(fixup)・編集(reword)できる
  • リベースの注意点を理解し、安全にリベースを実行できる
  • クリーンなコミット履歴を維持できるようになる

実行環境と前提条件

本記事の内容は、以下の環境で動作確認を行っています。

項目 要件
Git 2.40以上
OS Windows 10/11、macOS 12以上、Ubuntu 22.04以上
ターミナル コマンドプロンプト、PowerShell、Terminal.app、bash等
エディタ VS Code推奨

前提条件として、以下の知識があることを想定しています。

  • コマンドライン操作の基礎知識(cdls/dirmkdir等)
  • テキストエディタの基本操作
  • Gitの基本コマンド(git initgit addgit commitgit log)の理解
  • ブランチの基本操作(git branchgit switch)の理解
  • マージの基本的な理解

Gitのバージョンは以下のコマンドで確認できます。

1
git --version

git rebaseの基本

リベースとは何か

リベース(rebase)とは、あるブランチの変更を別のブランチの先端に「移植」する操作です。ブランチの分岐点を変更し、まるで最新の状態から作業を始めたかのように履歴を書き換えます。

gitGraph
   commit id: "C1"
   commit id: "C2"
   commit id: "C3" tag: "main"
   branch feature
   commit id: "C4'"
   commit id: "C5'" tag: "feature (リベース後)"

リベース前はC2からfeatureが分岐していましたが、リベース後はC3(mainの最新)から分岐したように履歴が書き換えられます。

リベースでは、featureブランチのコミット(C4、C5)がmainブランチの最新コミット(C3)の後に「再適用」されます。このとき、元のコミット(C4、C5)は新しいコミット(C4’、C5’)として作り直されます。コミットハッシュが変わることに注意してください。

git rebaseの基本構文

git rebaseコマンドの基本構文は以下のとおりです。

1
git rebase <ベースブランチ>

このコマンドは、現在のブランチのコミットを指定したベースブランチの先端に移植します。

基本的なリベースの実行例を見てみましょう。

1
2
3
4
5
# featureブランチに切り替え
git switch feature

# mainブランチの先端にリベース
git rebase main

実行結果の例:

1
Successfully rebased and updated refs/heads/feature.

リベースの実践

実際にリベースを体験してみましょう。

 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
# 練習用ディレクトリを作成して移動
mkdir git-rebase-practice
cd git-rebase-practice

# Gitリポジトリを初期化
git init

# 最初のファイルを作成してコミット
echo "# My Project" > README.md
git add README.md
git commit -m "Initial commit"

# mainブランチで追加のコミットを作成
echo "## 概要" >> README.md
git add README.md
git commit -m "Add overview section"

# featureブランチを最初のコミットから作成
git switch -c feature HEAD~1

# featureブランチで変更を加える
echo "config.json" > .gitignore
git add .gitignore
git commit -m "Add gitignore"

echo "node_modules/" >> .gitignore
git add .gitignore
git commit -m "Ignore node_modules"

この時点での履歴を確認します。

1
git log --oneline --graph --all

実行結果:

1
2
3
4
5
* 3f4g5h6 (HEAD -> feature) Ignore node_modules
* 2e3f4g5 Add gitignore
| * 1d2e3f4 (main) Add overview section
|/
* a1b2c3d Initial commit

mainfeatureが分岐していることがわかります。ここでリベースを実行します。

1
2
# featureブランチをmainの先端にリベース
git rebase main

実行結果:

1
Successfully rebased and updated refs/heads/feature.

リベース後の履歴を確認します。

1
git log --oneline --graph --all

実行結果:

1
2
3
4
* 7h8i9j0 (HEAD -> feature) Ignore node_modules
* 6g7h8i9 Add gitignore
* 1d2e3f4 (main) Add overview section
* a1b2c3d Initial commit

featureブランチのコミットがmainブランチの先端に移動し、履歴が一直線になりました。

マージとリベースの違い

履歴の形状の違い

マージとリベースは、どちらもブランチを統合するための手法ですが、履歴の形状が大きく異なります。

マージの場合:

gitGraph
   commit id: "C1"
   commit id: "C2"
   branch feature
   commit id: "C4"
   commit id: "C5"
   checkout main
   commit id: "C3"
   merge feature id: "M" tag: "マージコミット"

リベースの場合:

gitGraph
   commit id: "C1"
   commit id: "C2"
   commit id: "C3" tag: "main"
   branch feature
   commit id: "C4'"
   commit id: "C5'" tag: "feature"

マージでは分岐した履歴がそのまま保持され、マージコミットで統合されます。一方、リベースでは履歴が一直線に整理されます。

マージとリベースの比較

観点 マージ リベース
履歴の形状 分岐を保持 一直線に整理
コミットハッシュ 変わらない 変わる
マージコミット 作成される 作成されない
履歴の追跡 分岐点がわかる 分岐点が消える
公開ブランチへの適用 安全 危険(後述)
コンフリクト解消 一度で完了 コミットごとに発生

使い分けの指針

マージとリベースの使い分けには、以下の指針が参考になります。

マージを使うケース

  • 公開済みのブランチを統合する場合
  • 機能ブランチの作業履歴を残したい場合
  • チームで共有しているブランチの場合
  • マージの事実を履歴に残したい場合

リベースを使うケース

  • ローカルでのみ作業しているブランチの場合
  • プルリクエスト前に履歴を整理したい場合
  • 最新のmainブランチの変更を取り込みたい場合
  • クリーンな履歴を維持したい場合

一般的なワークフローでは、ローカルで作業中はリベースで履歴を整理し、プルリクエスト後のマージはマージコミットを作成する、という使い分けがよく行われます。

インタラクティブリベースの活用

インタラクティブリベースとは

インタラクティブリベース(git rebase -i)は、リベースの過程で各コミットに対してさまざまな操作を指定できる強力な機能です。コミットの順序変更、統合、メッセージ編集、削除などが可能です。

1
git rebase -i <対象のコミット>

<対象のコミット>には、編集したいコミットの一つ前のコミットを指定します。例えば、直近3件のコミットを編集したい場合はHEAD~3を指定します。

インタラクティブリベースのコマンド一覧

インタラクティブリベースを開始すると、エディタが開き、以下のようなtodoリストが表示されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
pick a1b2c3d First commit
pick b2c3d4e Second commit
pick c3d4e5f Third commit

# Rebase 1234567..c3d4e5f onto 1234567 (3 commands)
#
# 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

主要なコマンドの意味は以下のとおりです。

コマンド 短縮形 説明
pick p コミットをそのまま使用
reword r コミットを使用し、メッセージを編集
edit e コミットを使用し、修正のために停止
squash s 前のコミットに統合(メッセージも統合)
fixup f 前のコミットに統合(メッセージは破棄)
drop d コミットを削除

squashによるコミットの統合

squashは、複数のコミットを一つに統合し、コミットメッセージも統合する操作です。

実際にsquashを使ってみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 練習用の状況を作成
mkdir squash-practice
cd squash-practice
git init

echo "# TODO App" > README.md
git add README.md
git commit -m "Initial commit"

echo "- Add task" >> README.md
git add README.md
git commit -m "Add task feature"

echo "- Complete task" >> README.md
git add README.md
git commit -m "Add complete feature"

echo "- Delete task" >> README.md
git add README.md
git commit -m "Add delete feature"

現在の履歴を確認します。

1
git log --oneline

実行結果:

1
2
3
4
d4e5f6g (HEAD -> main) Add delete feature
c3d4e5f Add complete feature
b2c3d4e Add task feature
a1b2c3d Initial commit

3つの機能追加コミットを1つにまとめたいとします。

1
git rebase -i HEAD~3

エディタが開くので、以下のように編集します。

1
2
3
pick b2c3d4e Add task feature
squash c3d4e5f Add complete feature
squash d4e5f6g Add delete feature

保存してエディタを閉じると、コミットメッセージを編集するエディタが開きます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# This is a combination of 3 commits.
# This is the 1st commit message:

Add task feature

# This is the commit message #2:

Add complete feature

# This is the commit message #3:

Add delete feature

メッセージを整理して保存します。

1
2
3
4
5
Add task management features

- Add task feature
- Complete task feature
- Delete task feature

実行結果:

1
2
3
4
[detached HEAD e5f6g7h] Add task management features
 Date: Wed Jan 1 12:00:00 2026 +0900
 1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/main.

履歴を確認します。

1
git log --oneline

実行結果:

1
2
e5f6g7h (HEAD -> main) Add task management features
a1b2c3d Initial commit

3つのコミットが1つにまとまりました。

fixupによるコミットの修正統合

fixupは、コミットを前のコミットに統合しますが、統合されるコミットのメッセージは破棄されます。タイポ修正や小さな修正を本来のコミットに統合する際に便利です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 練習用の状況を作成
mkdir fixup-practice
cd fixup-practice
git init

echo "# API Documentation" > README.md
git add README.md
git commit -m "Add API documentation"

echo "## Endpoints" >> README.md
git add README.md
git commit -m "Add endpoints section"

# タイポを見つけて修正
sed -i 's/Endpoints/API Endpoints/' README.md  # Linux/macOS
# Windows PowerShellの場合: (Get-Content README.md) -replace 'Endpoints', 'API Endpoints' | Set-Content README.md
git add README.md
git commit -m "Fix typo"

「Fix typo」コミットを「Add endpoints section」に統合します。

1
git rebase -i HEAD~2
1
2
pick b2c3d4e Add endpoints section
fixup c3d4e5f Fix typo

実行結果:

1
Successfully rebased and updated refs/heads/main.
1
git log --oneline

実行結果:

1
2
f6g7h8i (HEAD -> main) Add endpoints section
a1b2c3d Add API documentation

「Fix typo」のコミットメッセージは履歴に残らず、変更内容だけが「Add endpoints section」に統合されました。

fixup用コミットの作成

git commit --fixupを使うと、あとで自動的に統合されるfixup用コミットを作成できます。

1
2
3
4
5
# 修正対象のコミットを指定してfixupコミットを作成
git commit --fixup=<対象コミットのハッシュ>

# 自動的にfixupを適用するリベース
git rebase -i --autosquash HEAD~3

--autosquashオプションを使うと、fixup!squash!で始まるコミットメッセージを自動的に適切な位置に配置し、対応する操作を設定してくれます。

rewordによるコミットメッセージの編集

rewordは、コミットの内容はそのままに、コミットメッセージだけを編集する操作です。

1
2
# 直近3件のコミットを対象にインタラクティブリベースを開始
git rebase -i HEAD~3
1
2
3
pick a1b2c3d Initial commit
reword b2c3d4e Add feature
pick c3d4e5f Fix bug

rewordを指定したコミットに到達すると、エディタが開いてメッセージを編集できます。

1
2
3
4
5
Add user authentication feature

- Implement login functionality
- Add session management
- Create logout endpoint

保存してエディタを閉じると、新しいメッセージでコミットが再作成されます。

リベース中のコンフリクト解消

コンフリクトが発生した場合

リベース中にコンフリクトが発生すると、リベースは一時停止します。

1
2
3
4
5
6
CONFLICT (content): Merge conflict in README.md
error: could not apply b2c3d4e... Add feature
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add <pathspec>", then run "git rebase --continue".
hint: You could also run "git rebase --skip" to skip this commit,
hint: or run "git rebase --abort" to cancel the rebase.

コンフリクトの解消手順

  1. コンフリクトが発生したファイルを確認
1
git status
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
interactive rebase in progress; onto a1b2c3d
Last command done (1 command done):
   pick b2c3d4e Add feature
Next commands to do (2 remaining commands):
   pick c3d4e5f Fix bug
   pick d4e5f6g Update docs
You are currently rebasing branch 'feature' on 'a1b2c3d'.
  (fix conflicts and then run "git rebase --continue")

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   README.md
  1. コンフリクトマーカーを確認して解消
1
cat README.md
1
2
3
4
5
6
7
8
# My Project
<<<<<<< HEAD
## Overview
This is the main project.
=======
## Description
This is a feature branch.
>>>>>>> b2c3d4e (Add feature)

ファイルを編集してコンフリクトを解消します。

1
2
3
# My Project
## Overview
This is the main project with new features.
  1. 解消したファイルをステージング
1
git add README.md
  1. リベースを続行
1
git rebase --continue

リベースの中断とスキップ

リベースを中断して元の状態に戻したい場合:

1
git rebase --abort

特定のコミットをスキップしたい場合:

1
git rebase --skip

リベースの注意点と安全な運用

公開ブランチへのリベースの危険性

リベースは履歴を書き換える操作です。すでに他の開発者と共有されている(プッシュ済みの)ブランチに対してリベースを行うと、深刻な問題が発生します。

flowchart TB
    subgraph your["あなたのローカル (リベース後)"]
        Y1[C1] --> Y2[C2] --> Y3[C3] --> Y4["C4'"] --> Y5["C5'"]
    end
    subgraph team["チームメンバーのローカル"]
        T1[C1] --> T2[C2] --> T3[C3]
        T2 --> T4[C4] --> T5[C5]
    end
    Result["同じ変更が異なるコミットとして存在し、履歴が混乱"]

絶対に守るべきルール

公開済み(プッシュ済み)のブランチはリベースしない

これはGitを使う上での基本ルールです。特に以下のブランチは絶対にリベースしてはいけません。

  • main/masterブランチ
  • developブランチ
  • 他の開発者がベースにしているブランチ
  • すでにプッシュしてプルリクエストを作成したブランチ

安全なリベースのワークフロー

  1. ローカルでのみリベースを使用する
1
2
3
# プッシュ前のローカルブランチでリベース
git switch feature
git rebase main
  1. プッシュ前に履歴を整理する
1
2
# プルリクエスト作成前にインタラクティブリベースで整理
git rebase -i main
  1. 強制プッシュが必要な場合は--force-with-leaseを使用する

どうしてもリベース後にプッシュが必要な場合(個人の機能ブランチで、他の人が使用していない場合のみ):

1
2
# 安全な強制プッシュ
git push --force-with-lease origin feature

--force-with-leaseは、リモートブランチが予期した状態であることを確認してからプッシュするため、--forceよりも安全です。

リベースからの復旧

誤ってリベースしてしまった場合、git reflogを使って復旧できます。

1
2
# reflogで履歴を確認
git reflog
1
2
3
4
5
e5f6g7h (HEAD -> feature) HEAD@{0}: rebase (finish): returning to refs/heads/feature
e5f6g7h HEAD@{1}: rebase (pick): Add feature
a1b2c3d HEAD@{2}: rebase (start): checkout main
d4e5f6g HEAD@{3}: commit: Add feature
c3d4e5f HEAD@{4}: commit: Initial setup
1
2
# リベース前の状態に戻す
git reset --hard HEAD@{3}

実践的なリベースのユースケース

ユースケース1: 最新のmainを取り込む

長期間作業していた機能ブランチに、最新のmainブランチの変更を取り込みます。

1
2
3
4
5
6
7
8
9
# mainブランチを最新化
git switch main
git pull origin main

# 機能ブランチに切り替え
git switch feature

# mainブランチの先端にリベース
git rebase main

ユースケース2: プルリクエスト前の履歴整理

プルリクエストを作成する前に、作業中に作った細かいコミットを整理します。

1
2
3
4
5
6
# mainブランチとの分岐点を確認
git merge-base main feature
# 出力: a1b2c3d

# 分岐点以降のコミットをインタラクティブリベース
git rebase -i a1b2c3d

ユースケース3: コミットの順序を変更

論理的な順序になるようにコミットを並べ替えます。

1
git rebase -i HEAD~4

エディタで行を入れ替えるだけで、コミットの順序を変更できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 変更前
pick a1b2c3d Add feature A
pick b2c3d4e Add feature B
pick c3d4e5f Fix feature A
pick d4e5f6g Add feature C

# 変更後(feature Aの修正をfeature Aの直後に移動)
pick a1b2c3d Add feature A
pick c3d4e5f Fix feature A
pick b2c3d4e Add feature B
pick d4e5f6g Add feature C

よくあるトラブルと解決策

リベース中にエディタが開かない

環境変数でエディタが設定されていない場合があります。

1
2
3
4
5
# VS Codeをエディタに設定
git config --global core.editor "code --wait"

# Vimを使用する場合
git config --global core.editor "vim"

リベースが複雑になりすぎた

途中でわからなくなった場合は、リベースを中断できます。

1
git rebase --abort

同じコンフリクトが何度も発生する

rerere(reuse recorded resolution)機能を有効にすると、一度解消したコンフリクトの解決方法を記録し、再利用できます。

1
2
# rerereを有効化
git config --global rerere.enabled true

まとめ

本記事では、Git rebaseの基本から実践的な活用法までを解説しました。

  • リベースの基本: ブランチの分岐点を変更し、履歴を一直線に整理する操作
  • マージとの違い: 履歴の形状、コミットハッシュの変化、使い分けの指針
  • インタラクティブリベース: squash、fixup、rewordによるコミット履歴の整理
  • 注意点: 公開ブランチへのリベースは厳禁、--force-with-leaseの活用

リベースは強力な機能ですが、履歴を書き換えるという性質上、慎重に使用する必要があります。「ローカルでのみリベースする」というルールを守りながら、クリーンなコミット履歴を維持していきましょう。

参考リンク