Gitでリモートリポジトリを巻き戻す

Gitで間違ったコミットをリモートリポジトリに push してしまった後に、それを無かったことにするには、リモート側での作業が必要だと思っていたのですが、ローカルからの操作でもできることがわかったので備忘録的に書いておきます。

次の状態にあるとします。アルファベットはコミットだと思ってください。

リモート: A-B-C       master
ローカル: A-B-C-D     master

ローカルで変更を加えてDの状態になっています。

git push すると次のようになるのですが、

リモート: A-B-C-D     master
ローカル: A-B-C-D     master

ここで、D は間違いだったと気づきました。

リモートリポジトリの master のバックアップ用のブランチを作ります。これは必須ではありませんが、念のため。

% git push origin master:master_bak

これで次の状態になります。

リモート: A-B-C-D     master
          A-B-C-D     master_bak
ローカル: A-B-C-D     master

リモートの master ブランチを削除します。

% git push origin :master
リモート: A-B-C-D     master_bak
ローカル: A-B-C-D     master

ローカルを一つ戻します。

% git reset HEAD^
リモート: A-B-C-D     master_bak
ローカル: A-B-C       master

リモートに push します。

% git push origin master
リモート: A-B-C       master
          A-B-C-D     master_bak
ローカル: A-B-C       master

すべてが順調にいって master_bak が要らなくなったら削除します。

% git push origin :master_bak
リモート: A-B-C       master
ローカル: A-B-C       master

最後のコミットを消す前にリモートリポジトリが誰かに pull されてたりしたら、その人が混乱するので一声かけるか、素直にあきらめましょう。

なんかもっと簡単にできるような気もするのですけどわかりませんでした。もっと良い方法を知っている人がいたら教えてください。

追記

コメントで id:akitsukada さんに教えてもらいました。

上記の

% git push origin :master
% git reset HEAD^
% git push origin master 

の手順は

% git push -f origin HEAD^:master

…と簡単にできるみたいです。

この場合はローカルのコミット状態は変わらないので、必要に応じて git reset などをやりましょう。