こんにちは!
中の人です。
あーコミットしてしまったぁぁ!元に戻したいぃぃ!
て時のコマンドですが、毎回調べてるので自分の整理も含めて紹介します
準備
一旦、
first commitしてoriginにpushしています
ファイルは
こんな感じです。
git revert
git revertは打ち消しのコマンドです。
履歴に残ります。
基本的な使い方
例えば
こんな感じでtest.htmlを変更しました。
で、
コミットしました。まだoriginにはpushしてません。
これを打ち消したい時
$ git revert [commit_id]
👇 つまり
$ git reset 5bf102b084cf4881488e747ed6e633de563cc392
これで打ち消せます
ちなみにオプションで
・-e (コミットコメントを書いてそのままコミットしたい時(オプションつけなければこれがデフォルトになります))
・-n (コミットまでしたくないとき(個人的にはこっちがおすすめ))
をつけることができます。
-eオプション(デフォルト)
今回はオプションをつけずにそのまま実行してみます。
つまり、オプションの-eが付いた内容で実行されるということですね
$ git reset 5bf102b084cf4881488e747ed6e633de563cc392
するとターミナルにエディタが表示されるので、適当にコメントを書きます。
(自分の場合は多分vimだと思いますが、環境によって違うかも?)
で、保存します。すると
コミット前のファイル内容に打ち消す形でコミットが作成され、コミットされました。
ふむふむ(゚∀゚ )
revertする前の状態に戻したい
revertする必要なかったぁ。。(´・ω・`)
というときあると思います。
revertする前の状態に戻したいぜ!というときは
・revertコミットにrevertコミットを作成する
と以前の状態に戻せます
つまり
-nオプション
$ git revert b279d67ce657f42fa9e417d2fee9bea49d559d60 -n // 👈今回は-nオプションを指定します。
これを実行すると
こんな感じで、revertのコミットを打ち消すコミットが作成されます。
今回は、-nオプションをつけたので、コミットまではされません。
個人的にはこっちの方が安心できます。
そしたら適当にコメント書いてコミットしちゃいます。
ついでにプッシュもしちゃいます。
プッシュした内容をrevertしたい
勢い余ってプッシュしたぁ。。(´・ω・`)
というときもありますよね。revertは打ち消しのコミットを作成してくれるので、前述した内容でコミット作成してプッシュすれば大丈夫ですね
つまり、今の状態は
こんな感じです。
$ git revert 2ff4ec7451f47c300bafc86a00eef95e5208815b -n
これで
プッシュする前のコミットが作成されるので、単純にoriginの状態を前回のものにしたければそのままプッシュしてもいいし、出来上がったコミットをいじって再度プッシュしてもいいでしょう
マージコミットをrevertしたい
勢い余ってマージしたぁ。。(´・ω・`)
という時もありますね
ということで適当にブランチ切ってマージした状態にします。
test_branchを切ってmasterにマージしてpushまでしました。
なんのコミットとなんのコミットがマージされたかが履歴に残ってるのを確認します。
ここでは、masterとtest_branchですね。
で、今私はmasterブランチにいます
そしたら、マージしたコミットは前述のrevertコマンドのように、マージしたcommit idのみを指定してもエラーになります
なので、revertするのはマージしたやつで、どっちのコミットを元に戻すか指定します
$ git revert -m 1 cdc317dd6e7116caf8df44ffe4c9b15480f04f0b -n
-m がマージコミットですよという意味のオプションで
1が今回はmasterのコミットを意味して、(どんなマージでも基本1を指定することになると思います)
2がマージ先を意味します。
ということで上記のコマンドを実行すると
$ git revert -m 1 cdc317dd6e7116caf8df44ffe4c9b15480f04f0b -n
こんなコミットが作成されました。
ちなみに
2を指定するとどうなるか見てみます
$ git revert -m 2 cdc317dd6e7116caf8df44ffe4c9b15480f04f0b -n
何も変化しませんでした。
ほー(゚∀゚ )
HEADが便利
大体revertするときは、今いる位置が基準になることが多いと思いますので、その場合はcommit idを指定せず
$ git revert HEAD
とすると、いちいちcommit idを指定せずrevertを実行することができます。
ということでrevertは以上です。
git reset
git resetは、文字通りリセットするコマンドです。
履歴に残りません。要は闇に葬りたいときに利用します。
基本的な使い方
そしたら、今の状態は
こんな感じです。
一旦、適当に変更してコミットします。
で、今の状態は
この変更をリセットしてみたいと思います
$ git reset [戻りたいcommit id]
👇 つまり
$ git reset 7bc2e828a28df5e8832b1c3eb3c412ed7e34cb52
ちなみにオプションで、resetとcommit idの間に
・ --soft (インデックスファイルや作業ツリーには影響を与えないで、コミット前に戻す(個人的にこれしか指定していない))
・ --mixed (インデックスをリセットするが、作業ツリーはリセットされない(今初めて知ったオプションなのでよくわかってない(デフォルトらしい)))
・ --hard (インデックスと作業ツリーがリセットされ、修正したファイルとか追加したファイルも消滅する。(個人的に一番恐怖を感じるオプション))
など指定することができます。
デフォルトが--mixedらしいのでそのまま実行してみます。
--mixedオプション(デフォルト)
$ git reset 7bc2e828a28df5e8832b1c3eb3c412ed7e34cb52
こんな感じて、コミットがリセットされ、変更がステージングにあがっていない状態になりました。
ふむふむ(゚∀゚ )
そしたら--softオプションを試してみます
--softオプション
git reset --soft 7bc2e828a28df5e8832b1c3eb3c412ed7e34cb52
コミットがリセットされ、変更ファイルがステージングに上がった状態になりました。
ほー(゚∀゚ )
--hardオプション
git reset --hard 7bc2e828a28df5e8832b1c3eb3c412ed7e34cb52
コミットがリセットされ、変更ファイルが消えました
わーぉ(゚∀゚ )
マージコミットをresetしたい
ということで適当にブランチ切ってマージします
今masterにいます
で、今の状態
こんな感じです。
masterのマージされる前に戻りたいので、
このcommit idを指定します。
$ git reset --soft 7bc2e828a28df5e8832b1c3eb3c412ed7e34cb52
こうなります。
マージされた内容が変更ファイルとして残ります。
ふー。。む?(゚∀゚ )
なので、マージコミットを--softや--mixedでresetした場合で、このままコミットを行うと、マージしたブランチから取り込んだ履歴がないのに、マージしたブランチの内容が反映されることになります。
ナンジャコリャ(゚∀゚ )
なのでマージコミットをresetする場合は、--hardオプションで実行したほうが、よくわからないgit logを残さなくて済むのかなと感じます。
また、先ほどのresetコマンドで、マージ先のcommit idを指定するとどうなるか見てみます。
$ git reset --soft aa2d8faa2ff6460a3c6c57c3e7eba221c639635d
masterとtest_2_branchが同じ位置にきました
ナンジャコリャ(゚∀゚ )
プッシュしたコミットをresetしたい
勢い余ってプッシュした場合、リモートの状態を前の状態にして、何も無かったことにしたい場合
今の状態をpushします
まずローカルを前の状態にresetします
前のmasterの位置は、
マージをrevertしました
の位置なので、
$ git reset --soft 7bc2e828a28df5e8832b1c3eb3c412ed7e34cb52
で、こいつの変更履歴をstashなりして一旦削除します
で、今の状態
ローカルのマスターが戻りました。
強制プッシュ
そしたら、このローカルの内容をリモートに強制的にプッシュします
$ git push -f origin master
originも戻りました。
闇に葬ってやったぜ!(゚∀゚ )
HEAD^が便利
revert同様、おそらくresetも今いる位置が基準になると思うので、commit idを指定しなくても、
HEAD^ (一つ前のコミットの位置を示す)
を使うとよくわからない操作をするリスクは減ると思います
$ git reset --soft HEAD^
ちなみに
resetは前述している通り、コミット履歴には残らないので、特にチーム開発の際はあまり推奨はされてなさそうです。
他のメンバーが、あれ?このコミットなくなってる。。。ムム?(゚∀゚ )
という状況はあまり好ましくないですからね
終わりに
gitてめちゃくちゃ便利だけど、利用してまもない時はビクビクしながら操作することが多いかと思います。(私は今でもそうです)
revert
reset
をひとまず覚えれば、ビビる必要もなくなるかなと感じます。
ただ、イケイケどんどんで考えなしに操作すると、後々うぉー(」°ロ°)」と白目むくことになるとなると思いますので、個人的には慎重に操作することに越したことないかなと思います
(resetで紹介した強制pushや、紹介してませんが強制pullなどあるので、どうしようもなくなった時でもなんとかなるっちゃなんとかなりますが)
私は不安な操作を行う場合は、今回のようにテストファイル作って、不安な操作を一度テストしてから本番でやるようにしています。
やっぱり怖いもんは怖いですからね!
お疲れ様でした。