できない.dev

git commit --amend した後にプッシュできない

amend はコミット SHA を作り直すため、push 済みブランチで amend するとリモートと履歴が分岐し non-fast-forward で拒否される。
自分専用ブランチなら `--force-with-lease`、共有ブランチなら追加コミットで修正するのが原則。

公開:

要約

git commit --amendコミット SHA を作り直す 操作なので、push 済みのコミットを amend すると履歴がリモートと分岐し、通常の push は non-fast-forward で拒否される。
自分専用ブランチなら --force-with-lease、共有ブランチなら amend ではなく追加コミットで修正、が安全な分岐点になる。

よくある原因

  1. amend で SHA 変化: メッセージ / ファイル変更が同じに見えても、内部的には新しい SHA を持つ別コミットになる。
  2. fast-forward 不成立: リモートの旧 SHA は新 SHA の祖先ではないため、Git は安全に取り込めず push を蹴る。
  3. オプション無し push: ただの git push では rewrite を反映できず、non-fast-forward で拒否される。
  4. 共有ブランチで amend: 他のメンバーが既に旧 SHA を取り込んでいると、後で衝突や重複コミットを生む原因になる。
  5. --force 素打ち: 他者の新規 push を上書きする事故になりやすい。
    共有ブランチで使うと履歴破壊。

解決策

1. 自分専用ブランチでは --force-with-lease

git commit --amend
git push --force-with-lease origin feature/my-branch

git-push 公式ドキュメント(新しいタブで開く) のとおり、--force-with-lease はリモートが想定通りの SHA の時だけ上書きするので、知らないうちに他者の push を踏みつぶす事故を防げる。

2. 共有ブランチでは追加コミットで修正

# amend せずに普通の修正コミットを足す
git add fix.txt
git commit -m "fix: typo in previous commit"
git push origin main

main など共有ブランチでは履歴書き換えを避け、修正コミットを追加する。git rebase -i を使った履歴整理は、自分のブランチが PR にマージされる前に限定する。

3. 誤って amend した場合の復旧

git reflog
# 例:
# a1b2c3d HEAD@{1}: commit (amend): ...
# 0e9f8e7 HEAD@{2}: commit: ...   ← amend 前の SHA
git reset --hard 0e9f8e7

git-commit 公式ドキュメント(新しいタブで開く) でも amend は新しいコミットを作る挙動と明記されており、元の SHA はガベージコレクション前なら reflog から復元できる。

4. --force は単独で使わない

# NG: 他者の push まで上書きする
git push --force origin main
 
# OK: リモートが想定通りの時だけ上書き
git push --force-with-lease origin main

共有リポジトリで素の --force を使うと履歴破壊の事故が起きる。
alias などで --force-with-lease を既定にしておくと安全。

実行例

実際に alpine/git 環境で上記の手順を動かすと、amend によって SHA が fdcd260 から 13666b4 へ作り直され、通常の push が non-fast-forward で拒否(終了コード 1)された後、--force-with-lease で forced update が成功(終了コード 0)することを確認できる。

== versions ==
git version 2.54.0
== run ==
--- セットアップ: bare リモート + クローン + 初回 push ---
warning: You appear to have cloned an empty repository.
push 済み SHA: fdcd260
--- push 済みコミットを amend(SHA が作り直される)---
amend 後 SHA : 13666b4
--- git push(non-fast-forward で rejected を想定)---
To /tmp/tmp.oOkIpH/remote.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to '/tmp/tmp.oOkIpH/remote.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
push の終了コード: 1
--- 解決: 自分専用ブランチなので --force-with-lease で上書き ---
To /tmp/tmp.oOkIpH/remote.git
 + fdcd260...13666b4 main -> main (forced update)
force-with-lease の終了コード: 0
--- 参考: reflog には amend 前の SHA も残る(reset --hard で復旧可能)---
13666b4 HEAD@{0}: commit (amend): init (amended)
fdcd260 HEAD@{1}: commit (initial): init

— 2026-07-08 時点の出力

この記事は役立ちましたか?