Gitおさらい:リモートリポジトリの巻き戻し

10月のRails案件でgitを使って、相変わらずのgit力の無さを痛感したので、覚えているうちにそん時やったことを復習しとくよ。ちなみにGitの操作は全部IntelliJから行ってます。途中、コマンド叩くことあるかなと思ってたけど、そんな事無かった。IntelliJのgitサポートは意外にあなどれない。:-)


復習につかったリポジトリは、片平堂(id:yuichi_katahira)作Androidアプリの「つぶのみ」をforkしたヤツ(GitHub - masanobuimai/tsubunomi)。大分前にforkして、からかい半分でKotlin化して飽きたままになってた。forkした自分が飽きているウチに本家の片平堂版は改修を続けてコミットグラフが伸びてていろいろ都合がよかったのが選んだ理由(片平堂さま、大変失礼しました&ありがとうございます。


愚かしい事に、forkした自分のリポジトリでは、masterを直接いじってたのだけど、それもまた今回の練習に都合がよかった。ちなみに、作業する前のリポジトリの状態は以下のとおり(katahirado、masanobuimaiはGitHub上のそれぞれのリモートリポジトリを指す。


これをどうしたいかというと、まず最初に自分のリモートリポジトリをキレイにしたい。


要するに master に直接行った自分の作業を他のブランチ(kotlin)に避けたい。ローカルにリポジトリをcloneしないことには始まらないので、そこからやる。IntelliJのスタート画面にある「Check out from Version Control」から「GitHub」を選んでcloneを作るよ。


ちなみに、この選択肢はGitHubプラグインを有効にしてないと出ないのでご注意を。Clone Repositoryに必要な情報を入れてclone実行。


cloneした直後のローカルリポジトリの状態はこんな感じ。


コミットグラフの(1), (2)をmasterから避けたいので、まずは対比先のブランチ:kotlinを作って、こんな風にしたい。


IntelliJでgitのブランチを作る方法はいくつかあるが、一番わかりやすい?のはステータスバーのカレントブランチ部分をクリックして、そこのメニューからブランチを作る。


IntelliJから操作したgitへの作業が、どんなコマンドが実行されているかは、ツールウィンドウ「Version Control」から確認することができる。


上のスクリーンショットは適当なヤツを貼っているのだけど、ブランチ作成で実行したgitコマンドは次のとおり。

git checkout -b kotlin


これで master ブランチを巻き戻(reset)してリモートリポジトリへpushするだけ...では無い見たい。変更がローカルリポジトリだけであれば、それで十分なのだが、すでにリモートリポジトリに変更(masterへの(1)と(2)のコミット)されていると、ローカルリポジトリを巻き戻してpushでは不十分なんですと。


で、どうやるかというと、

するそうな。てっきり、ローカルリポジトリから強制上書きみたいなことできるのかと思ってたら、そうではなくて「削除して作り直す」んだと。さらに厄介なことに、GitHubの場合、デフォルトブランチ(通常はmaster)は削除できない制約があるそうな。実際に削除を試みると、以下のようなエラーで弾かれる。

! [remote rejected] master (deletion of the current branch prohibited)


どうするかというと、master以外のブランチをデフォルトブランチにすれば良い。そのため、先ほどローカルリポジトリに作ったブランチ:kotlinを早々にpush。新しいブランチをpushするので「Push current branch to alternative branch」をチェックしとく。


ちなみに、実行したコマンドはこれ。

git push origin kotlin:kotlin


これでリモートリポジトリにはブランチがmasterとkotlinの2つできたことになる。


GitHubでデフォルトブランチを変更するには、そのリポジトリの管理画面(Adminリンク)に行き「Default Branch」を変更するだけでよい。


デフォルトブランチをkotlinに変えたことで、リモートリポジトリのmasterブランチを削除できるようなった。IntelliJからリモートリポジトリのブランチを削除する場合は、以下のように削除対象のブランチを選択すればよい。


これてっきり「リモートリポジトリの解除」かと思ってたけど、そうではないのね。実際に実行されたgitコマンドはこんなのだった。

git push origin :refs/heads/master


なにはともあれ、これでリモートリポジトリから master ブランチは削除されたことになる。でもって、ローカルでmasterの巻き戻しやる前にこの作業してて正解だったのかもしんない。


(たぶんGitHub固有の)諸準備に手間取ったけど、本来やりたかったmasterブランチの巻き戻しを行う。いわゆるWEB+DB PRESS vol.50 p.88の「あとからブランチを作る」そのものなので、巻き戻しはHARD Resetで行う。"HEAD^"みたいな相対記法の覚えが悪いのでハッシュ値を指定して巻き戻す。


まずは巻き戻したい場所のハッシュ値を得る。良くを言えば、ここから直接 reset を実行できれば尚良いのだけど、今んとこ、そこまで気の利いたことはできないみたい。


Git Resetの実行は、VCS->Git->Reset HEADで。と、その前にカレントブランチがkotlinになっているので、それをmasterに切り替える。ブランチの切替もステータスバーからやると簡単。実行してるコマンドは当然「git checkout master


カレントブランチをmasterに戻して準備が出来たので巻き戻し(reset)を実行する。「Reset Type」は「Hard」を選び、「To Commit」に先ほどコピーしたハッシュ値を入れる(Validateボタンを押すと、そのコミットの詳細みせてくれる。


一応、実行したコマンドはこんなの。

git reset --hard 3ff9344


これにてめでたくローカルリポジトリが思惑通りのコミットグラフになる。


で、先と同じようにmasterブランチをリモートリポジトリにpushする。実行したコマンドは「git push origin master:master」ね。


これでリモートリポジトリも思惑通りのコミットグラフになる。


リモートリポジトリにmasterブランチが復活したので、忘れないうちにデフォルトブランチをkotlinからmasterに戻して作業完了。念のためSourceTreeで見てみたコミットグラフは以下のとおり。


ここまでやって、ホントにやりたかった事の前準備ができただけなので、まだ続く。やめれば良かったと、ちと後悔してる。:-P