---
title: "git squashとは：コミットをまとめる4つの手順とfixup・push済みブランチの扱い"
url: "https://www.issoh.co.jp/tech/details/2506/"
published: 2024-06-13
updated: 2026-09-27
categories: ["開発"]
publisher: "株式会社一創"
---

# git squashとは：コミットをまとめる4つの手順とfixup・push済みブランチの扱い

作業中に「タイポ修正」「レビュー指摘対応」「やっぱり戻す」といったコミットが積み上がり、プルリクエストを開いたら30件並んでいた——というのはよくある状況です。ここで必要なのは、コミットを減らすこと自体ではなく、**後から履歴を読む人が意思決定を追える形に畳み直すこと**です。この操作は一般に「git squash」と呼ばれますが、Gitに `git squash` というサブコマンドはありません。この記事では、squashの正体を先に押さえたうえで、コミット粒度の判断基準、`git rebase -i` と `--fixup` によるまとめ方、`git reset --soft` と `--root` を使う手順、GitHubのマージ設定でローカル作業ごと省く方法、そして畳んではいけない場面の見分け方を、Gitの公式ドキュメントとリリースノートの記述に沿って整理します。掲載したコマンドは、Git 2.55系の一時リポジトリで実行して結果を確かめています。

## まとめ

コミットが多すぎる履歴を整理する判断は、次の順で決まります。

| 状況            | 取るべき手段                  | コマンド                    |
| ------------- | ----------------------- | ----------------------- |
| 未push・自分のブランチ | 対話的にsquash / fixup      | git rebase -i HEAD\~10  |
| レビュー指摘の追加修正   | fixupコミットを自動整列          | git commit –fixup=SHA   |
| メッセージだけ直したい   | rewordで内容を保持            | –fixup=reword:SHA       |
| 直近n件を即座に1件へ   | HEADだけ戻して再コミット          | git reset –soft HEAD\~n |
| 最初のコミットまで畳む   | ルートからrebase             | git rebase -i –root     |
| ブランチ全体を1件に畳む  | マージ時にsquash             | git merge –squash       |
| チーム全体で標準化     | GitHubのSquash and merge | リポジトリ設定で強制              |
| push済み・共有ブランチ | 畳まない                    | —                       |

表のSHAは、まとめ先またはメッセージの修正対象となるコミットの識別子です。実行時はこの表記を対象コミットのSHAに置き換えて指定します。

最も効く一手は、個々の開発者に `rebase` を徹底させるのではなく、GitHubのマージ方式をスカッシュマージに固定してしまうことです。ローカルの履歴がどれだけ散らかっていても、mainに残る履歴はプルリクエスト単位の1コミットに揃います。以下、squashの定義、粒度の基準、各手段の使い分けを順に見ていきます。

## git squashとは：専用コマンドは無く複数コミットを1つに畳む操作の総称

「git squash」は、連続する複数のコミットを1つのコミットにまとめる操作を指す通称です。`squash` という語が正式に登場するのは、[git-rebaseのドキュメント](https://git-scm.com/docs/git-rebase)が定める対話的rebaseのアクション名（`squash` と `fixup`）と、[git-mergeの \--squash オプション](https://git-scm.com/docs/git-merge)の2か所です。単独のサブコマンドとしては存在しないため、そのまま打つと次のように拒否されます。

```
$ git squash
git: 'squash' is not a git command. See 'git --help'.
```

結果として同じ「1つにまとまった履歴」を作る経路は4つあります。対話的rebaseで行ごとにsquash・fixupを指定する方法、`--fixup` で予約しておき `--autosquash` で自動整列させる方法、`git reset --soft` でHEADだけを戻して再コミットする方法、`git merge --squash` やGitHubのSquash and mergeでブランチ単位に畳む方法です。前の3つは自分のブランチの履歴を書き換える操作、最後の1つは取り込む側で新しい1コミットを作る操作という違いがあります。この違いが、後半で扱う「push済みのブランチで使ってよいか」の判断にそのまま効いてきます。

チームでsquashをどこまで使うかは、ブランチ戦略とマージ方式の取り決めの一部です。運用ルール全体の決め方は[Git運用のベストプラクティスとブランチ戦略・コミット規約の決め方](https://www.issoh.co.jp/column/details/2379/)で扱っています。

## コミットが多すぎる履歴で実際に壊れるもの：bisectとrevertの精度低下

「履歴が汚い」という表現は主観的ですが、コミットが細かすぎる状態で具体的に機能しなくなるものは特定できます。

一つは `git bisect` による原因特定です。bisectは各コミットが単体でビルド・動作することを前提に二分探索します。「途中まで書いたコミット」「後続コミットとセットで初めて動くコミット」が混ざっていると、探索の途中でビルドが通らないコミットに当たり、そのたびに `git bisect skip` で対象を飛ばす操作が必要です。skipが増えるほど探索範囲は絞り込めなくなり、バグ混入地点の特定精度が落ちます。

もう一つは `git revert` による切り戻しです。対象コミットが連続していれば `git revert --no-commit <最古>^..<最新>` のように範囲でまとめて取り消せます（git-revertのドキュメントも「Sets of commits can also be given」と明記しています）。問題は、1つの機能が15コミットに分散し、しかも他の変更と交互に並んでいる場合です。この状態では範囲指定が使えず、対象コミットを1件ずつ拾って順に指定する作業になります。プルリクエストが1コミットに畳まれていれば、revertは1回で済みます。

逆に言えば、bisectもrevertも使わない小規模なリポジトリでは、コミット数が多いこと自体の実害は限定的です。整理の労力に見合うかは、そのリポジトリで履歴を実際に遡る運用があるかで判断してください。[コードレビューの進め方や観点](https://www.issoh.co.jp/tech/details/13384/)を設計する際にも、この前提は共有しておくと合意が早くなります。

## どこからが多すぎか：レビュー単位とrevert単位で決めるコミット粒度の基準

コミット数の適正値を「1PRあたり何件まで」と数で決めても機能しません。100行の設定変更と3,000行の機能追加では妥当な件数が違うためです。数ではなく、コミットの中身で判断します。

### レビュー単位・revert単位で切るコミットの分け方とgit add -pでの分割

基準として実用的なのは、**そのコミット単体でレビューでき、単体で取り消せるか**です。この条件を満たすコミットは、後から見ても「何を、なぜ変えたか」が閉じています。

分割すべき組み合わせのうち最も効くのは、フォーマッタの一括適用を単独コミットにすることです。数千行規模の差分が出るため、他の変更を同じコミットに含めるとレビュー対象が完全に埋もれます。次に効くのがリファクタリングと機能追加の分離で、これを混ぜるとレビュアーは「変数名の変更」と「ロジックの変更」を差分から目視で切り分ける作業が必要です。ライブラリのバージョン更新も、それに伴うコード修正とは分けておくと、後で更新だけを戻せます。

作業を進めてから分けたい場合は、`git add -p` でファイル内の変更をハンク単位で選んでステージし、複数コミットに切り出せます。ステージし忘れた分を直前のコミットに含めるだけなら、使うコマンドは `git commit --amend` です。コマンドの使い分けは[用途別のGitコマンド早見表](https://www.issoh.co.jp/tech/details/2787/)にまとめています。

コミットの中身そのものの考え方は[Gitが変更履歴を記録する仕組みと粒度・メッセージ設計](https://www.issoh.co.jp/tech/details/13558/)で扱っています。メッセージの書式を `feat:` `fix:` のような接頭辞で統一したい場合は[Conventional Commitsの書き方とtype一覧](https://www.issoh.co.jp/tech/details/4691/)が参考になります。

### 畳むべき作業過程のコミットと残すべき意思決定のコミットの見分け方

整理対象になるのは、単体では意味を持たないコミットです。「typo修正」「レビュー指摘反映」「デバッグログ削除」「WIP」といったメッセージのコミットは、直前の本体コミットに吸収させて構いません。これらは作業過程の記録であって、意思決定の記録ではないためです。候補の洗い出しは `git log --oneline -i -E --grep='WIP|typo|デバッグ'` のようにメッセージで絞り込むと早く終わります（`-i` と `-E` は連結して `-iE` と書くと認識されません）。

一方で、次のコミットは件数が増えても残す価値があります。優先して残すべきは障害対応で意図的に入れた暫定対処で、後から必ず問われるのが、なぜその場しのぎを選んだかという判断の理由です。性能改善で採用した実装とその測定条件、外部仕様の変更に追随した修正も同様に、「なぜその選択をしたか」がコミット単位で参照されます。畳んで1つにすると、後から `git log` や `git blame` で辿れる情報が失われます。

## ローカルでのgit squash：対象範囲と作業時点で選ぶ4系統の手順

ローカルでまとめる手段は大きく4系統あり、まとめたい単位と作業タイミングで選び分けます。

### git rebase -i でsquashとfixupを指定し直近のコミットを1つに畳む

直近のコミットを対話的に畳む基本形です。まとめたい範囲を `HEAD~n` で指定します。

```
$ git log --oneline -5
a1b2c3d typo修正
e4f5a6b レビュー指摘対応
0c7b349 デバッグログ削除
d1a90e1 ログイン機能を追加
4f2e8ab READMEを更新

$ git rebase -i HEAD~4
```

エディタが開いたら、残す1件を `pick` のままにし、吸収させたいコミットを `squash`（`s`）または `fixup`（`f`）に書き換えます。行の並び順がそのまま適用順になるため、まとめ先のコミットを上に移動させる編集も同時に行えます。

```
pick d1a90e1 ログイン機能を追加
f 0c7b349 デバッグログ削除
f e4f5a6b レビュー指摘対応
f a1b2c3d typo修正
```

`squash` と `fixup` の違いはコミットメッセージの扱いだけです。squashは畳んだ全コミットのメッセージをエディタで結合・編集させます。fixupは吸収される側のメッセージを破棄し、そのまま使うのはまとめ先のメッセージです。「typo修正」のような残す価値のないメッセージを消したい場面では、fixupを選べば確認画面が出ない分だけ手数が減ります。

### –fixupと–autosquashによる修正先の指定と自動整列

`rebase -i` のエディタ内で手作業で行を並べ替えるのは、コミット数が増えるほど間違えやすくなります。Gitには、まとめ先をコミット時点で宣言しておき、rebase時に自動で並べ替える仕組みがあります。

レビュー指摘に対応する時点で、修正対象のコミットのSHAを指定します。

```
$ git commit --fixup=d1a90e1
$ git log --oneline -2
9f8e7d6 fixup! ログイン機能を追加
a1b2c3d typo修正
```

コミットのタイトルに `fixup!` という接頭辞が自動で付きます。git-rebaseのドキュメントによれば、autosquashが認識する接頭辞は `squash!`、`fixup!`、`amend!` の3種です。接頭辞に続くタイトルまたはハッシュから対象コミットを特定し、todoリスト内で対象コミットの直後へ移動させたうえで、アクションを `pick` から `fixup` 等へ自動的に書き換えます。

```
$ git rebase --autosquash HEAD~5
```

ここで押さえておきたいのが実行条件です。[Git 2.44.0のリリースノート](https://github.com/git/git/blob/master/Documentation/RelNotes/2.44.0.adoc)には『”git rebase –autosquash” is now enabled for non-interactive rebase, but it is still incompatible with the apply backend.』と記載されており、**2.44以降は `-i` を付けなくても `--autosquash` が動作します**。既定のmergeバックエンドでは有効ですが、`--whitespace` などでapplyバックエンドに切り替わる場合は併用できません。2.44より前は対話モードとの併用が必須だったため、`rebase -i --autosquash` と書かれた解説はその頃の記述が残っているものです。使用中のバージョンは `git --version` で確認できます（2026年9月時点の安定版は2.55系で、2.56はリリース候補の段階です）。手元の2.55系でも、`fixup!` コミットを含む3件に非対話の `git rebase --autosquash HEAD~3` を掛けると、エディタを開かずに2件へ畳まれることを確認しました。

なお、起点に `main` を指定すると最新mainへの載せ替えも同時に走り、コンフリクトが発生しうる点には注意してください。自分のコミットを畳むだけなら、上の例のように `HEAD~n` を指定します。

設定で常用する場合は適用範囲に差があります。git-rebaseのドキュメントは `rebase.autoSquash` について「interactive rebaseの既定として有効化する」と説明しており、**設定値が効くのは対話モードのみ**です。非対話のrebaseで自動整列させたい場合は、設定の有無にかかわらず `--autosquash` を明示する必要があります。

メッセージも含めて差し替えたい場合は、Git 2.32.0で追加された派生形を使います。`--fixup=amend:<commit>` は内容とログメッセージの両方を置き換え、`--fixup=reword:<commit>` で置き換える対象はメッセージだけです。[git-commitのドキュメント](https://git-scm.com/docs/git-commit)によれば、rewordは `--fixup=amend: --only` の短縮形で、インデックスにステージした変更を無視します。コミットメッセージの誤りだけを後から直したい時に、内容を巻き込まずに済みます。

### git reset –soft でエディタを開かずに直近n件を1コミットへまとめ直す

対話画面での行編集すら不要で、「直近の数件を丸ごと1件にしたい」だけなら `git reset --soft` が最短です。[git-resetのドキュメント](https://git-scm.com/docs/git-reset)が説明するとおり、`--soft` はインデックスと作業ツリーに触れず、HEADの位置だけを指定コミットへ戻します。戻した分の変更はステージ済みのまま残るため、そのまま1回コミットすれば畳み終わります。

```
$ git log --oneline
c5e0a91 c5
7d21b3f c4
0a9f6e2 c3
c51bf1d c2
8b00558 c1

$ git reset --soft HEAD~3
$ git commit -m "c3〜c5をまとめる"
$ git log --oneline
989bde5 c3〜c5をまとめる
c51bf1d c2
8b00558 c1
```

この方法は途中のコミットを選べず、戻した範囲のメッセージもすべて捨てます。まとめ先を選びたい、あるいは一部のコミットだけ残したい場合は `rebase -i` を使ってください。`--soft` を `--hard` と打ち間違えると作業ツリーの変更まで消えるため、実行前に `git status` で未コミットの変更が無いことを見ておくと安全です。

### git rebase -i –rootによる初期コミットを含む履歴全体の集約

`HEAD~n` は親コミットを基準に数えるため、リポジトリの最初のコミット（ルートコミット）を範囲に含められません。初期コミットごと1件に畳みたい場合は、git-rebaseのドキュメントにある `--root` を指定します。上流を指定する代わりに、ブランチから到達できるすべてのコミットを対象にするオプションです。

```
$ git rebase -i --root
```

開いたtodoリストの先頭行を `pick` のまま残し、2行目以降を `fixup` に書き換えて保存すると、ブランチの履歴が1コミットになります。手元の検証でも、3件あった履歴が先頭コミットのメッセージを持つ1件にまとまりました。テンプレートから作ったリポジトリの試行錯誤を消して公開したい、といった場面向けの操作です。すでに他人がcloneしているリポジトリでは、全コミットのSHAが変わるため使わないでください。

### git merge –squashによる作業ブランチ全体のmainへの1件集約

個々のコミットを選ばず、作業ブランチの成果をまとめて1コミットにする手段です。

```
$ git switch main
$ git merge --squash feature/login
$ git commit -m "ログイン機能を追加"
```

`merge --squash` は変更内容を作業ツリーとインデックスに反映するだけで、コミットは作りません。実行すると `Squash commit -- not updating HEAD` と表示され、HEADは動かないまま変更だけがステージされます。マージコミットも作られないため、mainには通常のコミットが1件追加される形になります。ブランチ内の履歴は捨てられるので、途中の意思決定を残す必要がないタスクブランチ向きです。squashで取り込んだコミットは親を1つしか持たないため、あとで取り消すときも`-m`の指定が要りません。取り消し側の手順は[git mergeの取り消し方法とabort・reset・revert -mの使い分け](https://www.issoh.co.jp/tech/details/17755/)にまとめています。

## GitHubのSquash and merge設定：mainの履歴をPR単位に統一

ここまではローカルでの操作ですが、チーム開発で最も確実なのは**整理をローカルに任せないこと**です。rebaseの習熟度は開発者ごとに差があり、「レビュー前にsquashしてください」という運用ルールは守られない前提で設計したほうが破綻しません。GUIクライアントで対話的リベースを行う場合の操作とreflogでの復旧手順は[Sourcetreeの使い方｜インストールから認証・カスタムアクションまで](https://www.issoh.co.jp/tech/details/17494/)にまとめています。

### リポジトリ設定でスカッシュマージを強制し既定のコミットメッセージを選ぶ

GitHubのリポジトリ設定では、マージ方式を選択する場所は Settings > General > Pull Requests です。スカッシュマージのみを許可し、他の方式のチェックを外せば、プルリクエストのマージ時に必ず1コミットへ畳まれます。開発者はブランチ内でいくらコミットを刻んでも構わなくなり、mainの履歴はプルリクエスト単位で揃います。

同じ設定画面で、スカッシュ時の既定コミットメッセージ形式も選べます。[GitHubのドキュメント](https://docs.github.com/ja/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/configuring-commit-squashing-for-pull-requests)によれば、既定形式（コミット1件ならそのタイトルと本文、2件以上ならプルリクエストのタイトルとコミット一覧）に加えて、「プルリクエストのタイトルのみ」「プルリクエストのタイトルと説明」「プルリクエストのタイトルとコミットの詳細」から選択できます。

この項目は既定のままにせず、「プルリクエストのタイトルと説明」を選ぶことを推奨します。既定形式はコミット2件以上の場合に散らかったコミット一覧をそのままメッセージ本文へ流し込むため、「typo修正」「WIP」といった消したかった文字列がmainの履歴に残ります。畳んだ意味が薄れるのはこのパターンです。プルリクエストの説明欄に変更理由を書く運用と組み合わせれば、履歴に残るメッセージの品質はレビュー時点で担保されます。

マージ方式ごとの履歴の違いは[GitHubの「プルリクエストのマージについて」](https://docs.github.com/ja/pull-requests/reference/pull-request-merges)にまとまっています。スカッシュマージで作られるのは、ブランチ側のコミットとは親子関係を持たない新しい1コミットです。この性質が、後述するFAQの「マージ後のローカルブランチの扱い」に効いてきます。

### gh pr merge –squash でターミナルからスカッシュマージを実行する手順

ブラウザを開かずにスカッシュマージする場合に使うのは、GitHub CLIの `gh pr merge` です。[gh pr mergeのマニュアル](https://cli.github.com/manual/gh%5Fpr%5Fmerge)によれば、`-s`（`--squash`）でコミットを1つに畳んでベースブランチへマージし、`-t` と `-b` で畳んだコミットの件名と本文を指定できます。`-d` を付けるとマージ後にローカルとリモートのブランチを削除します。

```
$ gh pr merge 128 --squash --delete-branch \
    --subject "ログイン機能を追加 (#128)" \
    --body "パスワード認証とセッション管理を追加"
```

必須チェックが通っていない段階で `--auto` を付けると、条件を満たした時点で自動マージされる予約になります。スクリプトからマージ操作を定型化したいときの入口として、ghのインストールと基本操作は[ghコマンド（GitHub CLI）のインストール方法と主要コマンド一覧](https://www.issoh.co.jp/tech/details/3547/)で確認してください。

## 履歴の書き換えを避けるべき場面とpush済みコミットをsquashする際の安全策

### squash・rebaseを行ってはいけない共有ブランチと影響を受ける3つの相手

コミットを畳む操作は履歴の書き換えです。**すでにpush済みのブランチを他人が参照している場合、rebaseもsquashも行うべきではありません。**git-rebaseのドキュメントは「他人が作業のベースにしているブランチをrebase（その他あらゆる書き換え）するのは悪手であり、下流にいる全員が自分の履歴を手作業で修正させられる。本当の解決策は、そもそもupstreamをrebaseしないことだ」と明言しています。

該当するのは、レビュアーが手元にチェックアウトしているブランチ、別の作業ブランチの分岐元になっているブランチ、CIが特定のSHAを参照して動いているブランチです。これらを書き換えると、相手の `git pull` が意図しないマージを起こしたり、[Gitで変更が衝突する仕組みと解消手順](https://www.issoh.co.jp/tech/details/13562/)で扱うようなコンフリクトを人為的に発生させたりします。どのブランチが共有扱いになるかは、feature・develop・releaseといったブランチの種類と役割で決まります。整理の前提は[Gitブランチの種類とブランチ戦略の解説](https://www.issoh.co.jp/tech/details/3892/)を参照してください。

### push済みのコミットを自分のブランチでsquashしリモートへ反映する手順

push済みでも、自分しか使っていない作業ブランチであれば畳んで構いません。プルリクエストを開く前に履歴を整えたい、という場面がこれに当たります。手順は、リモートの最新を取り込んでからローカルで畳み、安全策付きのforce pushで上書きする3段階です。

```
$ git fetch origin
$ git switch feature/login
$ git rebase -i origin/main
  （todoリストでまとめたい行を fixup に書き換えて保存）
$ git log --oneline origin/main..HEAD
$ git push --force-with-lease --force-if-includes origin feature/login
```

`git log origin/main..HEAD` で、mainに無い自分のコミットだけが意図した件数になっているかを確かめてからpushします。プルリクエストのレビューがすでに始まっている場合は、畳む前にレビュアーへ一声かけてください。GitHub上では既存のレビューコメントが古い差分に紐づいたまま残り、どの指摘がどこに反映されたかを追いにくくなるためです。

### force push時の追跡ref照合とローカルへの取り込み確認による安全策

自分専用のブランチで書き換えた履歴をリモートへ反映するには、force pushが必要です。`git push -f` をそのまま使うと、自分のfetch以降に他人が積んだコミットを黙って消します。代わりに `--force-with-lease` を使うのが一般的な推奨ですが、これにも既知の穴があります。

```
$ git push --force-with-lease --force-if-includes origin feature/login
```

[Git 2.30.0のリリースノート](https://github.com/git/git/blob/master/Documentation/RelNotes/2.30.0.adoc)には『”git push –force-with-lease\[=<ref>\]” can easily be misused to lose commits unless the user takes good care of their own “git fetch”.』と書かれています。`--force-with-lease` はリモート追跡refが指すコミットとリモートの現状を照合する仕組みです。ところがIDEやエディタがバックグラウンドで `git fetch` を走らせていると、その追跡refだけが先に更新されます。ローカルへ取り込んでいないのに照合は通る状態になり、他人のコミットを消せてしまいます。

この穴を塞ぐのが、同じく2.30.0で追加された `--force-if-includes` です。[git-pushのドキュメント](https://git-scm.com/docs/git-push)によれば、リモート追跡refの先端がローカルブランチのreflogから到達可能かを検証します。つまりリモートの更新をローカルへ実際に取り込んだ後で書き換えたかを確認し、そうでなければforce updateを拒否します。バックグラウンドfetchによる見かけ上の一致では通りません。

ただし適用条件があります。git-pushのドキュメントは、`--force-with-lease` を指定せずに渡した場合、または `--force-with-lease=<refname>:<expect>` のように期待するコミットを明示した形と併用した場合、`--force-if-includes` は “no-op”（何もしない）になると明記しています。単独で付けても効果はないため、上記のように引数なしの `--force-with-lease` とセットで使ってください。

## GitHubでコミット履歴とコミットIDを確認しsquashの結果を検証する手順

リポジトリの更新履歴（コミット履歴）を画面から辿る経路は3つあります。

ブランチ全体の履歴を見るには、ファイル一覧右上にあるコミット件数のリンク、またはURL末尾を `/commits/<ブランチ名>` にします。特定ファイルの変更履歴だけを追う場合は、ファイル表示画面の「History」から辿ります。行単位で「いつ・誰が・どのコミットで」変更したかを見るなら「Blame」表示です。畳みすぎた履歴の弊害は、このBlame表示で最も体感しやすくなります。

各コミットの右側に表示される7桁の英数字がコミットID（SHA-1ハッシュ）の短縮形です。完全な値は40桁で、コミット画面右上のコピーボタンから取得できます。`git rebase -i` や `--fixup=` に渡す際は、短縮形の7桁でも一意に定まれば受け付けられます。

2つのブランチやコミットを比較する場合は、URL末尾を `/compare/<base>...<head>` の形式にします。GitHubのドキュメントが説明するとおり、三点ドットは共通の祖先（マージベース）とhead側の最新状態との差分を示します。base側の最新状態と直接比べたい場合は二点ドット（`..`）を使い分けてください。

手元で履歴の分岐を視覚的に確認したい場合は、[VS Codeでコミット履歴・ブランチを可視化するGit Graph](https://www.issoh.co.jp/tech/details/9201/)を使うと、rebase前後の変化を図で追えます。

## 受託開発での判断：squashを標準にする条件と履歴を残すリポジトリ

ここまでの手段を踏まえ、当社が受託開発のリポジトリでマージ方式を決めるときの線引きを言い切っておきます。

**スカッシュマージを標準にするのは、次の3条件がそろうリポジトリです。**1つ目は、プルリクエストが1機能・1修正の単位で切られていること。2つ目は、切り戻しの単位がプルリクエストと一致していること。3つ目は、変更理由をプルリクエストの説明欄に書く運用が回っていることです。この3つがそろえば、mainの1コミットがそのままリリースノートの1行とrevertの1回に対応し、履歴の読み手も保守の引き継ぎ先も迷いません。

反対に、**スカッシュを標準にしないほうがよいのは、1本のプルリクエストが数週間生きる大型ブランチを抱えるリポジトリ**です。途中の設計判断が数十コミットに分かれて記録されており、1件に畳むと `git blame` から辿れる根拠が消えます。この場合に選ぶのは、マージコミット方式を残し、ブランチ内だけ `--fixup` と `--autosquash` で作業過程のコミットを畳む運用です。外部委託先と社内チームが同じリポジトリを触る体制でも、誰がどの判断をしたかをコミット単位で残す要求が出やすく、同じ扱いになります。

マージ方式は、ブランチ保護・必須チェック・自動デプロイとセットで決めないと途中で崩れます。CIの必須チェックを通ったプルリクエストだけをスカッシュマージで入れ、mainへの到着をデプロイの起点にする、という構成までまとめて設計したい場合は、当社の[DevOps・CI/CD導入支援](https://www.issoh.co.jp/service/system/devops/)でリポジトリ運用からパイプライン構築まで対応しています。

## よくある質問

### コミットは何件までにまとめるのが正解ですか？

件数の正解値はありません。判断基準はコミット単体でレビューでき、単体でrevertできるかです。3,000行の機能追加なら10件でも妥当ですし、設定ファイル1行の変更が3コミットに分かれていれば多すぎます。

### rebase -i を途中で間違えました。元に戻せますか？

rebase実行中なら `git rebase --abort` で開始前の状態に戻ります。完了後に気づいた場合は `git reflog` でrebase前のHEADのSHAを探し、`git reset --hard <sha>` で復帰できます。保持期間は種類で異なり、現在の先端から到達可能なエントリは既定90日（`gc.reflogExpire`）ですが、rebase前のHEADのように到達できなくなったエントリは既定30日（`gc.reflogExpireUnreachable`）です。復旧は早いほど確実です。`git reset --soft` でsquashした直後の取り消しも、同じくreflogから戻せます。

### rebase中にコンフリクトが起きた場合はどうしますか？

該当ファイルを修正して `git add` した後、`git rebase --continue` で次のコミットへ進みます。そのコミットの適用自体が不要だと判断したら `git rebase --skip` で飛ばせます。判断がつかない場合は `git rebase --abort` で開始前に戻し、コンフリクトの少ない範囲に区切り直してからやり直すのが安全です。

### –fixup で指定するSHAが分からない場合はどうしますか？

`git log --oneline` で対象コミットの短縮SHAを確認して指定します。修正箇所が特定のファイルに閉じているなら、`git log --oneline -- <ファイルパス>` で候補を絞り込めます。

### GitHubでスカッシュマージした後、ローカルのブランチはどう扱いますか？

スカッシュマージでは、ブランチ側のコミットとは親子関係を持たない新しい1コミットがmainに作られます。ブランチのコミット自体はmainに取り込まれた扱いにならないため、そのブランチは削除して `main` を取り直すのが確実です。同じブランチで作業を続けると、畳まれる前のコミットが再びプルリクエストに現れます。`git branch -d` が「not fully merged」として削除を拒否するのも同じ理由で、スカッシュマージ済みと確認できていれば `-D` で削除して問題ありません。

## 関連記事

- [Git運用のベストプラクティス｜ブランチ戦略・コミット規約・レビュー基準の決め方](https://www.issoh.co.jp/column/details/2379/)
- [コミットとは？Gitが変更履歴を記録する仕組みと粒度・メッセージ設計を実装視点で解説](https://www.issoh.co.jp/tech/details/13558/)
- [Conventional Commitsとは？書き方・type一覧とSemVer連携を実例で解説](https://www.issoh.co.jp/tech/details/4691/)
- [Gitコマンド一覧｜用途別早見表とよく使う基本コマンドの使い方を解説](https://www.issoh.co.jp/tech/details/2787/)
- [Gitブランチとは｜種類（feature/develop/release/hotfix）とブランチ戦略をわかりやすく解説](https://www.issoh.co.jp/tech/details/3892/)
- [コンフリクトとは？Gitで変更が衝突する仕組みと解消手順・予防設計を実装視点で解説](https://www.issoh.co.jp/tech/details/13562/)
- [Git Graphの使い方｜VS Codeでコミット履歴・ブランチを可視化する拡張機能](https://www.issoh.co.jp/tech/details/9201/)

---

出典: [git squashとは：コミットをまとめる4つの手順とfixup・push済みブランチの扱い](<https://www.issoh.co.jp/tech/details/2506/>)（株式会社一創）
