2
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?

うっかり main ブランチに push したときの安全な戻し方(revert / cherry-pick)

Posted at

はじめに

GitHub をつかった開発で「あ!修正中のコミットをまちがって main ブランチに push してる... :fearful:」となったときのおはなしです。
最近、うっかりやらかしてしまって冷や汗をかきました。
そのときの対処法を備忘録としてまとめます。

まず、落ち着く

あわてて作業すると、ミスがミスを呼びさらに状況が悪化することがままあります。
そうなったら最悪。なので、まずは深呼吸して落ち着きましょう。
あわてたところで時間は戻らないのです。
それから、関係者(チームメンバーや上司など)に状況を共有しておくのがよいでしょう。

Revert で元に戻す

1. 打ち消したいコミットの SHA を確認する

git log --oneline
  • git log --oneline で、コミット履歴を確認します。
  • 打ち消したいコミットの SHA ハッシュをメモっておきます。
a1b2c3d うっかりコミットC
e4f5g6h うっかりコミットB
i7j8k9l うっかりコミットA
d0e1f2g 正しいコミットX

2. Revert コマンドでコミットを打ち消す(コミットはまだしない)

すでにリモートに push してしまっているので、履歴を書き換える git reset は使いません。
代わりに git revert コマンドを使って、誤って pushしたコミットを打ち消します。

うっかりコミット A 〜 C を打ち消す場合は、以下のコマンドを実行します。
d0e1f2g は正しいコミットなので、打ち消しません。

# 複数の SHA を指定する場合(古い順に)
git revert --no-commit i7j8k9l e4f5g6h a1b2c3d

# 範囲指定を使う場合
git revert --no-commit d0e1f2g..a1b2c3d
  • git revert --no-commit <打ち消したいコミットの SHA> で、指定したコミットを打ち消します。

:page_facing_up: NOTE :

  • スペースで区切って複数の SHA を指定することができます。
  • ..を使った範囲指定も可能ですが、開始点は含まれない ので要注意 :warning: です。
    A..B は「A の直後から B まで」のようにみえるけど、実際には「A からは到達できないが、B からは到達できるコミットの集合」を意味します。ややこしい...)
  • スペースで区切って複数のコミットを列挙するほうが安全です。急いでいるときこそ、確実な方法を選ぶのがよきです。
  • 大量にコミットがあって列挙すんのたいぎぃなという場合だけ、細心の注意をはらって範囲指定を使います。
  • まとめて一つの revert コミットにしたい場合は、--no-commit (ステージングに置くだけでコミットしない)オプションを使用します。
  • --no-commit オプションがない場合、各コミットごとに revert コミットが作成されてしまいログが荒れるので要注意です。

3. 変更をコミットしてリモートリポジトリに push する

git commit -m "Revert: うっかりコミット A to C"
git push origin main
  • git commit -m <コメント> で revert した変更をコミットします。
  • git push origin main でリモートリポジトリに push します。

これで、誤って push した変更を元に戻すことができました。
ここまでできたら、まずは一安心です。

新しいブランチを作成して、変更を移動する

誤って push した変更を新しい feature ブランチに移動して開発を続けたい場合は、以下の手順で移動できます。

さっきの例のうっかりコミット A 〜 C を新しいブランチに移動します。

例(再掲)
a1b2c3d うっかりコミットC
e4f5g6h うっかりコミットB
i7j8k9l うっかりコミットA
d0e1f2g 正しいコミットX

1. 新しくブランチを作成する

git checkout -b feature/ukkari
  • git checkout -b <新しいブランチ名> で新しいブランチを作成して切り替えます。

:page_facing_up: NOTE :

  • この時点の main ブランチは、revert で元に戻した状態になっている前提です。

2. cherry-pick を使って新しいブランチに変更を移動する

git cherry-pick i7j8k9l e4f5g6h a1b2c3d
git push origin feature/ukkari
  • git cherry-pick <誤って push したコミットの SHA> で、誤って push したコミットを新しいブランチに適用します。
  • git push origin <新しいブランチ名> で新しいブランチをリモートリポジトリに push します。

:page_facing_up: NOTE :

  • cherry-pick も .. を使った範囲指定が可能です。が、やはり確実な方法としてスペースで区切って複数の SHA を指定する方法がおすすめです。
  • もし、cherry-pick 中にコンフリクトが発生した場合は、内容を修正(手動で解決)してから git cherry-pick --continue で再開します。

これで、誤って push した変更を新しいブランチに移動することができました。

そもそも、うっかり push を防ぐには

そもそも「あ!」ってならないように、なにかしらできることがないか調べてみたところ、GitHubの「ブランチ保護ルール」を設定する方法がありました。

こちらを設定しておくと、main ブランチへの直接 push を防止できるようです。
チームで開発している場合は、特に有効かもしれません。

おわりに

ミスはつきものです。にんげんだもの。
ミスをしたときに、いかに冷静に対処できるかが重要だと考えます。
また、ミスを未然に防ぐ仕組みをつくることも大切です。
今回の記事が、わたしと同じようなうっかりさんの参考になればうれしいです。

参考リンク

2
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
2
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?