作りたいものがありすぎる

40歳を過ぎてプログラミングを始めた人の顛末とこれからなど

Gitの履歴変更で盛大に失敗した話をメモベースで書く

GitHubに公開リポジトリを使ってアプリを作っているが、上げちゃいけないモノをアップしてしまったのをきっかけに色々やったメモです。要はバットノウハウ、失敗談、こんな風になっちゃだめですよという自分への戒めです。

そもそもの経緯

branchを二つ作って、個別に新機能を開発をしていた。

branchB(ゆっくり目の作業)で .gitignoreを編集した後 branchA(急ぎ目の作業)をcheckoutして別作業を続ける。

branchBでしていた .gitignore の設定がなくなった為、 branchAでgit add . すると 隠したいはずの追加ファイルがステージングに上がり、そのまま気付かずコミットしてしまう。(ぎゃー)

しばらくしてその事実に気付き、リモートリポジトリの履歴から該当ファイルを削除しようと以下の記事を見つつ試みる

Git リポジトリに上がっているファイルを履歴ごと消すには? - Qiita

Git ファイルの履歴を完全に削除する · GitHub

ところが、コマンドの意味を理解しないままガチャガチャと操作(ぎゃー)

禁断の git push -fを良くわからないまま実行する(ぎゃー)

何が起こったか?

まずはこいつを見てくれ、どう思う?

f:id:sakamata:20190302161920p:plain

すごく…複雑です。

盛大にやらかして色々やってこりゃ駄目だ終わった状態のリポジトリである。 画面にはローカルとリポートのbranch両方が表示されて同じコミットのコメントが複数にコピーされてしまっている。

何が起こったかを自分なりに理解した範囲で解説。

本当はもっと根本を理解してからまとめて述べた方が、為になると思うのだけど、自分がやりたいのはアプリの制作であってツールに振り回された顛末を詳しく分析することじゃない。従ってこんな風にややこしい自体にハマるGitという複雑なツールを理解できない俺が悪いのか、ツールが悪いのかという議論はしないし、受け付けない。(けど、こういう事じゃない?という見解は良かったらくれると助かります。)

git filter-branch --tree-filter "rm -f [消したいファイルパス]" HEAD

このコマンドですべての履歴から特定のファイルの履歴を消せるとあったので消したが、 上記サイトを参考に実行した、このコマンドかこの後行った操作が、どうも過去の履歴に渡るコミット時のhash値を変えるという操作だったらしい。そもそも変更されたファイルの状態からhashを生成しているっぽいので、もしかして履歴が変わればhash値もブロックチェーン的に変わる感じかな?

で、Gitのそもそも論の記事がある。

P117~P146あたりにrebase絡みでコミットのリビジョンについての解説がある。で、おそらく状況としては、履歴の書き換えをすることで、rebaseに近いhash値の書き換えが発生、それに気づかないまま、強制pushであるgit push -fを怖さも知らずに実行し、ローカル、リモート、それぞれで古い履歴を消さないまま、良くわからず複数のbranchで履歴の削除を繰り返した結果、複数の履歴が存在し、収集が付かなくなった。という事の様だ。

こえーよ、Gitまじこえーよ。理解してない人間が使っちゃいけないオーバーテクノロジーだよ。

そもそもの問題の発生は .gitignore ファイルを編集した状態で別branchをcheckoutした事が原因でこんなことになるとは思いもよらなんだ。カスケード破壊ってやつですか。

という事で、理解するのは諦めてこの後、何をしたかという話ですが…。

実は、履歴の変更をしようと決めた時点で、リモートリポジトリ非公開にしてから潰すつもりだったので、ローカルリポジトリにバックアップを取って、上みたいになるまで安心して弄り倒して壊しまくってました。

現在はバックアップを取ったリポジトリのbranchを整理してから master branch で該当ファイルの履歴からの削除を行いました。ヤバいファイルを履歴から完全に削除したのですが、どうもこれで コミット時のhash値は、初期のオリジナルの物とは変わってしまいました。どうもそれは仕方のない事らしいというのが昨日今日で調べた範囲で判明している事です。(そんなこと無いって見解と知識が欲しい)チーム開発でこれをやったら終わりですが、ほとんど個人でやっていたので、リセットさえすりゃ簡単な事態であった事は確かです。 しかし、これチームで履歴の編集をやらかす事態が発生すると、チーム全員に一旦 Cloneでやり直しをさせるって事になるのか…。これは申し訳ない事態だ。

Laravelの場合はせいぜい .envファイルのコピーと storage/log の chmod 777 位の手間ですが、他のプロジェクトでは色々面倒な初期設定も他のメンバーにしてもらわんといけないかもなので、履歴を書き換えるような事態は発生させてはいけませんね。

閑話休題。現在は奇麗になったリポジトリを再度リネームしてGitHubに上げたのと、開発環境から本番環境にpushするだけでデプロイできるようにサーバー側も再設定しました。(本当はSeleniumを挟んでデプロイ出来るような環境をそろそろ作りたいのですが)

今回のリポジトリの再設定の際は、これまで sourceTreeに頼りっぱなしでコマンドラインをあまり使ってませんでしたが、VPSサーバーにpushする際の.ssh/config やGit configをそこそこ設定したり、testでcommitした際は全てコマンドラインで作業を行い。以前よりはGUIに頼らず操作ができる様になってきた感じです。ですが、やはり分岐しまくったbranchの状況を追うにはGUIでの可視化が便利ですね。

という訳で履歴管理ツールに悩まされるなんていうアホな事態はとっとと終わらせてモノを作ります。