--squashオプションを使用してマージするとgit branch -dでブランチを削除できない
はじめに
Gitでは、マージする際に--squashオプションを使用できます。このオプションでトピックブランチをマージすると、git branch -dでブランチを削除しようとしたときにエラーが発生し削除できません。この記事ではその理由と対処法を紹介します。
挙動の確認
--squashオプションを使用せずにマージした場合
masterブランチの最新コミットからトピックブランチを作成し、コミットD、Eを作成した後、masterブランチにマージすることを想定します。
D---E [topic]
/
A---B---C [master]
トピックブランチの作成は以下のコマンドで行います。
$ git checkout -b branch-1
次に、branch-1ブランチでファイルを編集してコミットD、Eを作成します。続いて、masterブランチに切り替え、branch-1ブランチをマージします。
$ git checkout master
$ git merge branch-1
その後、branch-1ブランチをgit branch -dコマンドで削除すると、エラーなく削除できました。
$ git branch -d branch-1
Deleted branch branch-1 (was ead4d02).
このとき、masterブランチの履歴を見ると、コミットD、Eがmasterブランチに取り込まれていることがわかります。

ちなみに、このグラフはGit GraphというVS Code拡張機能を使用して表示しています。Git Graphを使用すると、ブランチのコミット履歴を視覚的に確認できて便利です。
Git Graph - Visual Studio Marketplace
--squashオプションを使用してマージした場合
masterブランチの最新コミットからトピックブランチを作成し、コミットF、Gを作成した後、masterブランチに--squashオプションを使用してマージすることを想定します。
F---G [topic]
/
A---B---C---D---E [master]
別のトピックブランチbranch-2を作成します。
$ git checkout -b branch-2
同じくファイルを編集してコミットF、Gを作成した後、masterブランチに切り替え、--squashオプションを使用してbranch-2ブランチをマージします。
$ git checkout master
$ git merge --squash branch-2
この時点でgit statusコマンドを実行すると、マージした内容はまだコミットされておらず、ステージング状態であることがわかります。--squashオプションを使用してマージした場合、masterブランチには直接変更が記録されず、このようにステージングエリアに適用されるのみとなります。そのため、この後にコミットする必要があります。
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test.txt
コミットを行うと、マージした内容がコミットされ、branch-2ブランチとmasterブランチは同一の内容となります。
$ git commit
その後、branch-2ブランチをgit branch -dコマンドで削除しようとすると、以下のようにエラーが発生します。
$ git branch -d branch-2
error: the branch 'branch-2' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D branch-2'
hint: Disable this message with "git config advice.forceDeleteBranch false"
このときのmasterブランチのコミット履歴は下記画像のようになります。コミット履歴にF、Gが存在せず、代わりに「Squashed commit of the following:」と書かれた新しいコミットが存在していることがわかります。

なぜ-dオプションで削除できないのか
gitのドキュメントには-dオプションの説明として下記のように記載があります。
Delete a branch. The branch must be fully merged in its upstream branch, or in
HEADif no upstream was set with--trackor--set-upstream-to.
Git - git-branch Documentation
つまり、-dオプションでブランチを削除するためには、そのブランチが完全にmasterブランチに取り込まれている必要があります。
オプションを使用せずにマージした場合、masterブランチにはトピックブランチのコミット内容がそのまま取り込まれます。一方で、--squashオプションを使用してマージした場合、トピックブランチのコミットがmasterブランチに取り込まれるわけではなく、変更内容が反映された新しいコミットがmasterブランチに作成されます。このため、-dオプションでは削除できません。
Git Graphで見ると、branch-2ブランチの線の先がmasterブランチの線とつながっていないことがわかります。これは、branch-2ブランチの内容が履歴としてmasterブランチに取り込まれたのではなく、変更内容をまとめた新たなコミットとして適用されたことを示しています。

削除するためには
エラーメッセージを見ると、削除したい場合はgit branch -Dを使用するように書かれています。
$ git branch -d branch-2
error: the branch 'branch-2' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D branch-2'
hint: Disable this message with "git config advice.forceDeleteBranch false"
公式ドキュメントによると、-Dオプションは--delete --forceのショートカットであり、ブランチを強制的に削除します。
Git - git-branch Documentation
このオプションを使用することで、masterブランチに完全に統合されていないブランチであっても削除することができました。
$ git branch -D branch-2
Deleted branch branch-2 (was 610c4d8).
-Dオプションで強制的に削除する場合は、必要なブランチを誤って削除しないように、変更した内容が統合先ブランチ(masterやmainなど)に反映されているか、本当にそのブランチが不要かなどを確認した上で行ってください。
おわりに
この記事では--squashオプションを使用してマージを行った際に、git branch -dでは削除できない事象について紹介しました。
この記事がどなたかのお役に立てれば幸いです。







