先日、チーム開発で使っていたGitHubリポジトリのmasterブランチを壊してしまうという事案を起こしてしまったので、その時の反省の意味も込めて復旧までの流れを記録しておきます。
発生事象
プルリクで開発中のブランチを誤って開発完了前にmasterへマージしてしまいました。
まずは報告
まずはリポジトリを使っているチームメンバー全体にGitHubのmasterブランチを壊してしまったことを報告し、masterブランチをGitHubから git pull
しないように周知しました。
今はまだ影響があるのはGitHubリポジトリだけですが、 git pull
等で問題のコミットを取り込んでしまうとメンバーのローカルリポジトリまで影響が広がってしまいます。
復旧方法の検討
GitHubでmasteへマージしたプルリクの変更を取り消すには二つの方法がります。
- Revert
- Reset
基本的にはリモートリポジトリのコミットログをResetで変更するのはご法度です。特にチーム開発ではGitHubリポジトリを巻き戻して他の開発者が使っているブランチのコミットを消してしまうと、そのブランチはGitHubリポジトリとのコミットログの整合性を失いマージ出来なくなってしまいます。
Revertを使うと、取り消したい変更のコミットログはそのままに、変更内容を元に戻すコミットを追加するためコミットログの不整合が起こることはありません。ただし、穴を掘ってそれを埋めるような無駄なコミットログが残ってしまいます。
特に今回取り消したかった変更は後々にマージ予定の開発中ブランチだったため、Revertでそのコミットログが途中まで残ってしまっていると後々マージするときに、コミットが重複することになり不整合が起こるのではないかという懸念があります。
また、masterブランチを壊してすぐに報告したので、問題となったコミットログを取り込んだメンバーが居なかったこともあり、GitHubリポジトリを巻き戻しても影響が無さそうです。
というわけで、今回はResetで問題のコミットの直前まで巻き戻してmasterブランチを修復することにします。
コミットを巻き戻す
ローカル
まずはGitHubのコミットログから巻き戻したい位置のコミットハッシュを探します。
今回は 98e795a までコミットを戻します。
Reset操作はローカルリポジトリのmasterブランチで行います。
git checkout master
git reset --hard 98e795a
リセットしたら git log で最新のコミットログが 98e795aになっていることを確認しておきましょう。
GitHubへ反映
ローカルリポジトリを巻き戻したら、それをGitHubにも反映します。
巻き戻しを反映するには git push --forceを使用しますが、GitHubでは特定のブランチに --forceオプション付きでのプッシュを禁止することができるので、その場合はリポジトリの管理権限を持ったメンバーに一時的に設定解除を依頼しておきましょう。(完了後には設定を戻すことも忘れないようにしましょう)
git push --force origin master
プッシュが完了したらGitHubのコミットログが復元していることを確認して完了です。
その後は、チームメンバーへの完了報告もお忘れなく
注意点
中盤にも記載しましたが、このリポジトリを巻き戻す方法は同じリポジトリを使っている他メンバーにも影響を与える操作です。取り消したいコミットを他のメンバーが既に取り込んでいる場合には使えないのでご注意ください。