TL;DR
誤ったブランチをマージしてpushしたあと、force pushがブランチ保護で使えない場合は git revert -m 1 で取り消せる。本記事では、revertとforce pushの違い、マージコミットのrevert方法、PRのコミット数が膨らむ仕組みまで解説する。
想定シナリオ
チーム開発中、本来マージすべきでないブランチを誤ってマージし、そのままpushしてしまった。git push --force-with-leaseで履歴を巻き戻そうとしたが、ブランチ保護ルールにより拒否される。
! [remote rejected] Cannot force-push to this branch
こうなったとき、履歴を書き換えずに変更を取り消すrevertが使える。
--force-with-leaseは、リモートの先頭が自分の認識と一致する場合のみforce pushを許可する安全版。ただしブランチ保護が有効なら、これも弾かれる。
revert と force push の違い
| revert | force push | |
|---|---|---|
| やること | 変更を打ち消す新しいコミットを追加 | 過去のコミットを消して履歴を上書き |
| 履歴 | 残る(追加のみ) | 書き換わる |
| ブランチ保護 | 🟢 通常のpushなので通る | 🔴 保護ルールで拒否される |
| チームへの影響 | なし | 他メンバーのローカルと不整合が起きうる |
結果(コードの状態)は同じでも、履歴の扱いが根本的に異なる。revertは安全だが、履歴にrevertコミットが残る点はトレードオフとして理解しておく必要がある。
マージコミットのrevertには -m 1 が必要
通常のコミットと違い、マージコミットには親が2つある。revertするとき、どちらの親の状態に戻すかを明示する必要がある。
git revert -m 1 <マージコミットのハッシュ>
-
-m 1→ 1番目の親(=マージ先ブランチ)の状態に戻す。誤マージの取り消しはほぼこれ -
-m 2→ 2番目の親(=マージ元ブランチ)の状態に戻す。使う場面はかなり限られる
-mを省略するとGitがエラーを返す。マージコミットのrevertでは必須のオプション。
実践手順:正しい変更だけ残してrevertする
以下は「正しい変更がparameter.tsの1ファイルだけで、他34ファイルはすべて誤マージ由来」というケースでの手順。
# 1. 正しいファイルだけ一時退避
# -m はラベル、-- 以降が対象パス
git stash push -m "parameter.ts only" -- packages/cdk/parameter.ts
# 2. その他の未ステージ変更を破棄(HEADの状態に戻す)
git checkout -- .
# ステージ済みの変更も戻す場合: git reset HEAD .
# 未追跡ファイルも消す場合: git clean -fd
# 3. リモートと同期
git pull origin <ブランチ名>
# 4. 誤マージだけrevert(正しいマージはそのまま残す)
git revert -m 1 <不要なマージのコミットハッシュ>
# 5. 退避した変更を戻してコミット
git stash pop
git add packages/cdk/parameter.ts
git commit -m "fix: restore parameter.ts changes"
# 6. 通常のpush(forceは不要)
git push origin <ブランチ名>
この手順で、差分はFiles changed: 1の状態に収まる。
PRのコミット数が膨らむ理由
revert後にPRを開くと「93 commits」のように大きな数字が表示されることがある。
これは、誤マージで取り込んだ相手ブランチのコミット群が履歴に残り続けているため。revertは「変更を打ち消すコミット」を追加するだけで、取り込んだコミット自体は削除しない。GitHubはマージ先ブランチにないコミットをすべてカウントするので、数字が膨らむ。
確認すべきはFiles changedタブ。ここに表示される差分が意図どおりであれば、コミット数の多さ自体はマージ判断に影響しない。
履歴を整理したい場合は、マージ時に Squash and merge を選ぶと、全コミットが1つにまとまった状態でマージ先に入る。
履歴の可読性について
revertやマージコミットが多い履歴は、あとから経緯を追いにくくなる。具体的には git blame で変更者を特定するときや、git bisect でバグの混入箇所を絞り込むときに追跡コストが上がる。
ただし、日常の開発では「現在のコード」と「差分」を見る場面がほとんどで、過去のコミット一覧を遡る頻度は高くない。正しい差分がマージされていれば、実務上の影響は限定的である。
とはいえ「影響が少ないから雑でいい」ということではなく、Squash and mergeの活用やコミットメッセージの明確化で、できる範囲で履歴の可読性を保つ意識は持っておきたい。
まとめ
| 状況 | 対応 |
|---|---|
| 誤マージをpush済み+force push禁止 | git revert -m 1 <ハッシュ> |
| 正しい変更だけ残したい | stash → pull → revert → stash pop → commit → push |
| PRのコミット数が多い |
Files changedが正しければマージ判断には影響しない。Squash and mergeで整理可能 |
| 履歴の可読性 | 実務への影響は限定的だが、Squash and mergeやコミットメッセージで可読性を保つ工夫を |