FULLALLGOL 技術ノート

squash マージの後にブランチへ足したコミットは、既定ブランチに入らない

2026-08-31

PR を出す。レビュー中に気づいて、同じブランチへ 1 コミット足す。
その間にマージされる。足した分だけが消える。

squash マージ運用のリポジトリで、2 日間に 4 回これを踏んだ。
同じ形の事故を数えると、半月で 7 件になった。

なぜ気づけないのか

squash はブランチのコミット群を 1 つに潰して既定ブランチへ載せる。
潰したあとのブランチ先端は既定ブランチの祖先にならない
だから git merge-base --is-ancestor は「未マージ」と言うし、
PR の画面は MERGED と言う。どちらも内容が入ったことの証明になっていない。

実際に踏んだ形を並べると、壊れ方の幅が分かる。

何が起きたか
マージ直後の追補撤回したはずの設計だけが残り、作り直した本命が丸ごと落ちた
push 自体が失敗リモート先端は 1 つ前のまま。ローカルでは完了して見えた
積んだ PRベース側だけが入り、上に積んだ側は 1 文字も届かなかった
空のマージコミットMERGED 表示なのに変更ファイル 0 件。件名は別 PR のものだった
自動コミット10 分ごとの自動バックアップが、マージ済みブランチへ積み続けた

PR の上に PR を積まない

衝突を避けるつもりで、2 本目の PR のベースを 1 本目のブランチに向けたことがある。
いわゆる stacked PR だ。

結果はこうなった。2 本目はそのベースブランチへマージされ、
1 本目は既定ブランチへ squash で入った。
squash は 2 本目のコミットを祖先として持たないので、2 本目の内容はどこへも届かない
それでいて両方 MERGED と表示される

発覚したのは、既定ブランチを grep して関数名が 0 件だったからだ。
デプロイの直前だった。気づかなければ半分だけの版を本番へ出していた

MERGED は状態表示であって、内容の保証ではない

ある PR は画面上 MERGED なのに、既定ブランチに 1 文字も入っていなかった。
マージコミットは変更ファイル 0 件の空コミットで、しかもメッセージが別 PR のものだった。
近い時刻に連続でマージしたときの取り違えと見ている。

同じセッションで出した他の 2 本は正しく着地していた。
つまりこれはPR 単位で起きる。「1 本確認したから大丈夫」にはならない。

確かめるのは状態ではなく内容だ。

git fetch origin
git show origin/main:path/to/file.ts | grep 'theFunctionYouAdded'

人が push しないリポジトリほど危ない

エディタの自動バックアップ機能が 10 分ごとにコミットするリポジトリで、
squash マージ済みのブランチに HEAD が残ったまま自動コミットが積み続けた
1 日分・9 コミットが既定ブランチに入っていなかった。

自動コミットは「今の HEAD」へ積むので、一度外れると人が戻すまで永遠に外れたままになる。
PR も出ないので通知もない。

危険なのは「ブランチを整理して」と言われた瞬間だ。
マージ済みに見えるブランチを消すと、そこにしか無い更新が消える。

実務ルール

落としたときの復旧

慌てなくていい。ブランチを消してもコミットオブジェクトは残る。

まとめ