GitHubで“Squash and merge”したブランチを安全に削除するツールを作ってみた

2021/11/05に公開

ブランチを squash-merge すると、デフォルトブランチへマージした履歴が残らないため、通常の方法 git branch -dでは削除できません。
下図の場合、トピックブランチである D のコミットを squash-merge するとデフォルトブランチの新規コミット E としてマージされます。すると git の履歴は B の子供となるため、トピックブランチとの関連性が失われます。

浮いてしまったトピックブランチを削除するには強制削除 git branch -D を行う必要があり、作業途中の他のブランチを誤って削除しないか常に不安がつきまといます。

これを解決するために作ったツールが gh poi です。(気軽に「ポイッ」と削除できるようにしたい)

どんなツール?

gh poi は、GitHub が公式で提供している GitHub CLI のサブコマンドとして動くエクステンションです。

GitHub CLI v2.0.0 (2021年8月リリース) 以降のバージョンからエクステンションの開発とインストールが可能になりました。
エクステンションとして提供することで、ツール毎に GitHub へのアクセストークンを発行する必要がなく手軽に利用することができます。

削除戦略

初めにも書きましたが squash-merge されたブランチは強制削除でしか消すことができません。gh poi も内部的には強制削除を実行しているため、削除対象のブランチを正しく判定することが重要です。

削除フロー

  1. gh repo view で、リモートのリポジトリ名を取得
  2. git コマンドを使い、カレントディレクトリに存在するブランチのコミットハッシュの一覧を取得
  3. gh api で前述のリポジトリ名とコミットハッシュに関連するプルリクストを全て検索する
  4. 検索結果を基に削除判定及びブランチの削除

削除の判定方法

ローカルの各ブランチにおける先頭のコミットハッシュに関連するプルリクエストの情報を取得し、プルリクストの状態がマージ済みであればローカルの作業は完了と見なし、削除可能と判定します。GitHub API を使ってチェックしているため、“Squash and merge” を含むどの方法でマージした場合でも削除判定を行えるのが最大の特徴です。
また、一旦作ったプルリクエストをクローズし、新たにプルリクエストを作り直すケースもあります。その場合はブランチに関連するプルリクエストが複数になりますが、1件以上マージ済みのプルリクエストがあり且つその他の関連ブランチが全てクローズ状態の場合に削除可能と判定しています。
オープンされたプルリクエストが残っていればローカルで作業を継続することがあり得るため削除対象には含めません。気軽にいつでも gh poi を実行して作業環境をクリーンアップできるようにしています。

その他にも、最初の工程でフォーク元リポジトリがあれば upstream のリポジトリ名も取得しているため、フォーク元へプルリクエストを出した場合も同様に削除判定が行えます。これは OSS へ貢献する場合などに役に立ちます。

最後に

squash-merge されたブランチを削除する方法は探すといくつか見つかるのですが、GitHub とは連携しておらず期待通りに綺麗に消せるツールは見つからなかったので今回自作することにしました。
もしこのプロジェクトが気になった方は、gh-poi から ⭐️ Star の登録もお願いします。
それでは☕️

Discussion