0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

間違えて push した commit を取り消す — `git reset --soft` と `--force-with-lease` の合わせ技

0
Posted at

feature ブランチで typo 混じりの commit を push してしまった。

ローカルだけなら --amend で済むが、リモートに上がった瞬間それでは足りなくなる。

前提:今どういう状態か

local:  A --- B --- C(mistake)  ← HEAD
remote: A --- B --- C(mistake)  ← origin/feature/xyz

やりたいのは「C をなかったことにして、正しい内容で push し直す」こと。

git reset --soft HEAD^ で commit だけ巻き戻す

git reset --soft HEAD^

--soft は HEAD の位置だけを1つ前に戻す。

ステージングエリアとワーキングツリーには一切触れない。

つまり C の変更内容はステージ済みのまま残る。

local:  A --- B  ← HEAD(ステージには C の差分が残っている)
remote: A --- B --- C(mistake)

reset のオプション比較

オプション HEAD ステージ ワーキングツリー
--soft 戻す そのまま そのまま
--mixed(デフォルト) 戻す 戻す そのまま
--hard 戻す 戻す 戻す

--hard は変更が完全に消える。取り消したいだけで変更内容は残したい場合は --soft 一択。

ステージに残っている差分を修正して commit し直す

# 必要な修正を加える
git add -A
git commit -m "fix: 正しいメッセージ"

git push --force-with-lease でリモートを上書きする

ローカルの履歴を書き換えたことでリモートと分岐し、fast-forward できない状態になったので、通常の git push は rejected される。

$ git push origin feature/xyz
 ! [rejected]        feature/xyz -> feature/xyz (non-fast-forward)

ここで --force を使えば通るが、他人の push を踏み潰すリスクがある。代わりに --force-with-lease を使う。

git push --force-with-lease origin feature/xyz

--force vs --force-with-lease

項目 --force --force-with-lease
他人の commit を踏み潰す する しない(reject される)
検証ロジック なし ローカルの remote-tracking ref とリモート HEAD を比較
チーム開発での安全性 低い 高い

git fetch した直後に --force-with-lease すると、ローカルの ref が最新に更新されているため安全弁が効かなくなる。fetch と force push をワンライナーで繋げないこと。

一連の流れ

# 1. 直前の commit を取り消す(変更はステージに残る)
git reset --soft HEAD^

# 2. 必要なら修正
git diff --cached          # ステージの中身を確認
vim src/main.ts            # 修正
git add -A

# 3. commit し直す
git commit -m "feat: 正しい内容で再 commit"

# 4. リモートに安全に force push
git push --force-with-lease origin feature/xyz

複数 commit を戻したいとき

HEAD^ の部分を変えるだけで対応できる。

# 直近 3 commit を取り消してステージに残す
git reset --soft HEAD~3

HEAD~N は N 個前の commit を指す。HEAD^HEAD~1 と同義。

すでに他のメンバーがその commit を元にブランチを切っている場合は、force push ではなく git revert で打ち消し commit を積むほうが安全。履歴を書き換えていいのは「自分しか触っていないブランチ」が原則。

reflog — やらかしたときの保険

reset 自体を間違えても reflog から復元できる。

git reflog
abc1234 HEAD@{0}: reset: moving to HEAD^
def5678 HEAD@{1}: commit: 間違えた commit
# reset 前の状態に戻す
git reset --soft def5678

reflog はローカルに残り続けるので、--hard で消した変更すら救出できる。ただしデフォルトで 90日 を過ぎると GC で消える。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?