--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
HEAD
if no upstream was set with--track
or--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
では削除できない事象について紹介しました。
この記事がどなたかのお役に立てれば幸いです。