リリース前日にGitリポジトリを吹っ飛ばした話

やらかしちゃったが、本番環境ではないのでここで投稿させていただきます。
（懺悔をします）

## 背景

プロジェクトのバージョン管理はGitとなり、社内が提供しているGitbucketサービスを利用していた。
そして、そのGitbukcetサービスは提供終了となり、2021年9末までに、とある外部Gitサービスに移行しなければならない。

普通のGit移行なので、下記の図の通りに、既存Gitをローカルにクローンし、BacklogサービスのGitにPushして移行するように設計した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260067/562fc987-7bf9-c336-6202-c85488628926.png)

もっと具体的に、手順を下記のように作成した

```shell
## ローカルにクローン
$git clone --mirror http://[旧gitbucket]/gitbucket/git/hoge/xxxxx.git ./

## Remoteにプッシュ
$git remote set-url --push origin https://[新git]/git/hoge/xxxxxxx.git
$git push --mirror
```

どう考えてもごく普通のGitリポジトリ移行であり、きっと楽勝だと思った・・

## 急に「ああ！！」ってメッセージが来た..

いよいよ本番移行の日になり、全体周知メッセージを出してから、担当者に移行開始を依頼した。
すぐに終わるだろうって思ったが、担当者から下記の連絡が来た


>移行はうまく行ってなかった。プッシュしたところ、ファイルサイズが大きすぎて失敗しました。
「exceeds file size limit of 100M」というメッセージが出ており、
リポジトリのサイズが大きいと思われる。
解決策として、Shallow Cloneして古い履歴を消してサイズを縮めればいけるかも

「検証の際に発生していない事象ですけど・・？」って思いながら、アプリ開発チームに連絡し、「数年前のGit履歴を消しても大丈夫」という回答をもらって、あまり深く考えずに担当者に「shallow cloneはOK」って依頼した。

お昼過ぎの頃、急に担当者から「ああ！！」ってメッセージがポップアップされ、下記の連絡が来た

>何か変なコマンド打ってしまったかもです。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260067/866377b9-39ec-e6bf-a082-2c357d5757e5.png)

事情を確認したところ、一瞬で頭の中でも真っ白になった
**旧Gitbukcetは、master以外のブランチ・タグ・コミット情報がすべてなくなった**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260067/7845e5ef-cef3-1ec4-4964-fb4b2b6702fa.png)

## 復旧のための努力

一般的に、障害発生した場合は下記の流れが一般的に考えられる

```
1. 二次障害の防止
2. 関係者への連絡
3. 現状の把握
4. 復旧手段の検討
5. 復旧実行
```

### 1. 二次障害の防止
まずは二次障害を防止するために、即座の作業停止、及び旧GitbukcetをPUSH・PULL厳禁のことを全体周知した。


### 2. 関係者への連絡
その後、APチームにリーダーと電話し、「Gitリポジトリのブランチを吹っ飛ばしたけど..」って伝えたら、「.....はい？」っていままでに聞いたことない声で返事され、「**明日の深夜に本番リリース予定ありますが、そのブランチはまだmasterにマージしていないけど...**」ってショックな事実が言われた。
復旧しないと、絶対許さない事件になってしまった...

### 3. 現状の把握
次は、担当者と一緒に現状を整理した

- 担当者の誤操作があった。具体的に`Shallow Clone`の検証として試してプッシュしたところ、**間違って旧Gitbukcetリポジトリをremoteとするところで操作してしまい、旧Gitbukcetへプッシュしてしまった**。更に、途中から問題を発覚して実行を中断させた。
- 上記の誤操作の結果、旧リポジトリにおいて、すべての`タグ・ブランチ・masterブランチ以外のコミット情報`がなくなった
- 担当者のローカルリポジトリは、一部のブランチ情報しかなかった

うーん..なかなか絶望...

### 4. 復旧手段の検討
最後の最後、下記の復旧するためのタスクを決めた

- 旧Gitbukcetリポジトリのバックアップ有無を探す
- 翌日の本番リリースのスナップショットを持っている人を探す
- ローカルリポジトリの残骸から部分的な復旧方法を探す
- 1時間後再度関係者を集めて状況共有する

アプリケーションメンバーの「どういうこと？」「ふざけるな」「こんなスナップショットはねぇよ！」って怒鳴を聞きながら、やっと朗報が来た。

>知見者＜対象のリポジトリは、Jenkinsより日単位ですべてのブランチ情報含めてバックアップされているよー

神かよ...
幸い本日中の新規PUSHがないので、バックアップを持ってリポジトリを復旧できそう！

### 5. 復旧実行
絶対二度と間違ってないように、きちんと手順を作成してレビューし、
ダブルチェックで下記のように復旧した

```
cd C:\work\[バックアップ]\

$ ブランチ確認
git branch -a

$ push 向け先変更
git remote set-url --push origin http://[旧gitbucket]/gitbucket/git/hoge/xxxxx.git

$ 向け先確認
git remote -v

$ Push実施
git push origin
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260067/bcba2bfe-a1f0-67a5-2eae-7015a1c9637b.png)

## 事件はなぜおこってしまったのか

お察しの通り、まるで教科書のように、いろんなアンチパターンを踏んでしまった。

- **手順書以外の操作をしてしまった**: 想定した手順がうまく行かないところ、作業の停止ではなく、試していろんな手順以外のコマンドを実行してしまった。
- **ダブルチェッカーがない**: 担当者一人で作業させてしまった
- **事象の原因調査の甘さ**: 発生した問題をきちんと原因分析・最適解決案の考慮をせず、提案をそのままに受け入れた
- **リカバリ手順がない**: 「万が一ためのリカバリ手順」を考慮していない。

本番環境作業なら絶対問われるチェックリストのものは、
安易で「知見者の基盤作業だから・・」って思ってしまい、今回一件も守れてなかった

## 二度と惨劇を起こさないため

普通なら「技術弱い人は作業ミス起きやすい」と思っていたが、実は逆で、「技術強いこそ、ミスしやすい」だと思う。
何故かというと、「俺は大丈夫だ」という自信感だ。
でも、人なら絶対ミス起きる。
技術強い人は、強い権限を持ってより根幹なところに作業するので、ミス起きたらより破壊力が強くなると思う。

`sudo`初回起動時の英語のメッセージを常に覚えるべき

```
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
```

今回のケースに限って、下記の再発防止策があると思う

- 手順記載のものしか実行しない
- 作業時ダブルチェックが必須
- リカバリ手順が必須
- 日頃のバックアップは重要


以上は僕の懺悔となります。長文を最後までに読んでいただきありがとうございます。