みなさん、こんにちは!日本のDevOps・インフラエンジニアです。
今回は、Gitの履歴を綺麗に保つための強力なテクニック、「`git merge –squash`」について、初心者の方にも分かりやすく解説していきます。
なぜ`git merge –squash`が重要なのか?
開発を進めていると、一つの機能を作るためにたくさんのコミットを作成することがありますよね。「 typo を修正」、「一時的な変更」、「テストコードを追加」など、細かなコミットが履歴にずらっと並んでしまうと、後からコードを追うのが大変になったり、変更内容を把握しにくくなったりします。
`git merge –squash`は、こうしたフィーチャーブランチ(機能開発用のブランチ)で積み重ねられた数多くのコミットを、まるで一つの大きな変更のようにまとめて、メインブランチ(例えば `main` や `master`)に統合できる機能です。これにより、メインの履歴がスッキリ保たれ、コードレビューや過去の履歴を辿る作業が格段にしやすくなります。
基礎知識:Gitのコミットとマージとは?
`git merge –squash`を理解するために、まずはGitの基本的な概念をおさらいしましょう。
コミット (Commit)
Gitにおけるコミットとは、ファイルの状態のスナップショット(記録)のことです。開発者はコードを変更したら、「コミット」という形でその変更を保存します。コミットには、変更内容の説明(コミットメッセージ)が付随します。
マージ (Merge)
マージとは、あるブランチで行われた変更を、別のブランチに取り込む操作です。例えば、フィーチャーブランチでの開発が完了したら、その変更をメインブランチにマージします。
Squash (潰す・圧縮する)
「Squash」は「潰す」や「圧縮する」といった意味合いです。`git merge –squash`では、フィーチャーブランチの複数のコミットを「1つのコミット」に圧縮するイメージで捉えてください。
`git merge –squash`の実装方法
では、具体的に `git merge –squash` を使ってフィーチャーブランチをメインブランチに統合してみましょう。
仮に、`feature/new-login` というフィーチャーブランチで作業していて、これを `main` ブランチに取り込みたいとします。
1. メインブランチに切り替える
まず、変更を取り込みたいブランチ(ここでは `main`)に移動します。
git checkout main
2. ローカルの `main` ブランチを最新の状態にする(推奨)
念のため、リモートの `main` ブランチの最新の状態をローカルに取り込んでおきましょう。
git pull origin main
3. `git merge –squash` を実行する
ここで、フィーチャーブランチを指定して `–squash` オプション付きでマージを実行します。
git merge –squash feature/new-login
このコマンドを実行すると、`feature/new-login` ブランチで行われた全ての変更が、ステージングエリア(次にコミットされる状態)に適用されます。しかし、まだコミットは作成されていません。
4. コミットを作成する
ステージングエリアに集まった変更を、一つのコミットとして `main` ブランチに記録します。
git commit -m “feat: Add new login functionality (squashed)”
ここで `-m` オプションで、この統合された変更内容を表す分かりやすいコミットメッセージを記述します。`squashed` と追記しておくと、後で履歴を見たときに「これはsquashされたコミットだな」と分かりやすくなります。
5. リモートリポジトリにプッシュする
ローカルの `main` ブランチに変更がコミットされたら、リモートリポジトリにプッシュします。
git push origin main
これで、`feature/new-login` ブランチでの一連の変更が、`main` ブランチに1つのクリーンなコミットとして統合されました!
サンプルプログラム(コマンド例)
以下は、上記の手順をまとめたコマンド例です。
1. メインブランチに切り替える
git checkout main
2. ローカルの main ブランチを最新の状態にする (リモートから取得)
git pull origin main
3. feature/my-feature ブランチの変更を squash して main ブランチに取り込む
feature/my-பிranch は、あなたが作業していたフィーチャーブランチ名に置き換えてください。
git merge –squash feature/my-feature
4. squash された変更を1つのコミットとして main ブランチに記録する
コミットメッセージは、変更内容が分かるように具体的に記述しましょう。
git commit -m “feat: Implement user registration and profile update (squashed)”
5. 変更をリモートリポジトリにプッシュする
git push origin main
コード内のコメント:
- `git checkout main`: `main` ブランチに移動します。
- `git pull origin main`: リモートの `main` ブランチの最新の変更をローカルに取得します。
- `git merge –squash feature/my-feature`: `feature/my-feature` ブランチの変更履歴をすべてまとめて、現在のブランチ(`main`)のステージングエリアに適用します。この時点ではコミットは作成されません。
- `git commit -m “…”`: ステージングエリアにある変更を、指定したメッセージで1つのコミットとして記録します。
- `git push origin main`: ローカルの `main` ブランチの最新のコミットを、リモートの `origin` リポジトリの `main` ブランチに送信します。
応用・注意点
履歴は綺麗になるが、親子関係は消失する
`git merge –squash` の最大のメリットは、メインの履歴がスッキリすることです。しかし、この操作を行うと、元々 `feature/my-feature` ブランチにあったコミットの履歴は `main` ブランチには引き継がれません。つまり、`main` ブランチから見ると、`feature/my-feature` ブランチがどこから分岐して、どのような変更を経てきたのかという「親子関係」や「詳細な変更履歴」が失われてしまいます。
そのため、後から「この機能の細かい開発経緯を追いたい」といった場合に、元々のフィーチャーブランチの履歴を辿ることが難しくなる可能性があります。
再マージの運用に注意
もし、`git merge –squash` で統合したフィーチャーブランチを、後で再度 `main` ブランチにマージしようとした場合、Gitは「すでに `main` ブランチにはこの変更が含まれている」と認識しないことがあります。なぜなら、`squash` されたコミットは、元々のフィーチャーブランチのコミットとは異なる新しいコミットだからです。
このような事態を避けるためには、`squash` マージを行った後、元のフィーチャーブランチを削除するか、あるいは `main` ブランチへのマージが完了したことを明示的に記録する(例えば、`git merge –no-ff feature/my-feature` のように、`–no-ff` オプションでフォークポイントを残すマージを別途行うなど)といった運用が考えられます。
どのような場合に使うべきか?
`git merge –squash` は、以下のような場合に特に有効です。
- 実験的なブランチでの作業: 試行錯誤の結果、最終的に一つの完成形だけをメインブランチに残したい場合。
- 一時的な修正ブランチ: 短期間で完了した小さな修正で、履歴を細かく残す必要がない場合。
- コードレビューでの指摘対応: レビューで指摘され、複数回にわたる修正を1つのコミットにまとめたい場合。
逆に、機能開発の過程を詳細に記録しておきたい場合や、後からブランチの履歴を追ってデバッグする機会が多い場合は、通常の `git merge` を使う方が適していることもあります。
`git merge –squash` をうまく活用して、皆さんのGit履歴をより管理しやすく、スマートな開発を実現してください!

コメント