1.はじめに
gitのrevertを理解しようとしたらrevertしたcommitは残ったままだったり、revert後にマージするとコンフリクトを起こったりして意味が分からず理解に苦しんだ。さらに、revertをrevertしたくっても何が起こるのか分からず、結果 「revert=使ってはいけない」 認識が染み付いてしまった。
だが意味がわかるとgitでの可能性が広まると感じたので調べてみたところ、遊戯王カードのチェーンに落とし込んだら理解ができたのでまとめてみた。
※ただし私は遊戯王エアプ勢なので細かいところは違うところもあるのと雰囲気で理解しているので悪しからず。
2.そもそもrevertとは?
下記サイトにはこのように記載がある
git revert コマンドは作業を前進させながら変更を安全に元に戻すことができる操作です。コミット履歴でコミットを削除したり隔離したりするのではなく、新しいコミットを作成して指定した変更を打ち消します。
要は変更を無効にするが、revertした履歴は残る操作である。
「revertした履歴が残る」というのがポイントであり、revertの難易度を上げている根源であると思っている。
3.gitでの挙動
以下で実際にgitを使って動きを見てみる。
3-0.事前準備
適当なブランチを用意して。とりあえず適当なファイル「test.txt」を作成しコミットする。
以降このファイルを書き換えたりして検証する。
3-1.普通にcommitする。
addしたファイルに対して、ファイルの中身を書き換えてcommitする。
※とりあえず、今回はファイルの文章を「first!!!」から「second!!!」に変える。
3-2.revertする。
「3-1」でcommitした内容をrevertで無効にする。
revertのコマンドは「git revert commitID」で行けるので、実行する。
そうするとrevertしたcommitの前の状態(「first!!!」の状態)に戻る。
3-3.revertをrevertする
revertを無効にしたい時にもrevertを実行する。
同じように「git revert commitID」でcommitIDにrevertしたIDを設定すると実行できる。
こうすると、revertした履歴を無効にするので、変更した内容(second!!!)が反映される。
4.遊戯王で例えてみた
実際に遊戯王で例えてみる。
ちなみにコストなど細かい遊戯王のルールは端折って今回必要なところだけ掲載しています。
4-1.今回使うカード
今回使うカードは「サンダーボルト」と「神の宣告」の2枚
ここではざっくり以下の処理とする。
- サンダーボルト:相手のフィールドのモンスターを全破壊する魔法カード
- 今回Gitでいうcommitの役割
- 神の宣告:魔法カードか罠カードが発動した時を無効にする罠カード
- 今回Gitでいうrevertの役割
詳細は以下を参照。
4-2.チェーン
revertを考える上で遊戯王には「チェーン」というのが存在する。
ざっくりカードAが発動したタイミングで別のカードBを発動した場合、「カードB→カードA」の順番で処理をするというものである。
詳細なルールは遊戯王wikiを参照。
4-3.実例
実際の遊戯王のプレーに沿って例えてみる。
①プレイヤーAが「サンダーボルト」を発動した後、チェーンで②プレイヤーBが「神の宣告」を発動し、更にチェーンして③プレイヤーAが「神の宣告」を発動したとする。
この時、カードの処理の順番は後に発動したカードからとなり、プレイヤーAの「神の宣告」から処理する。
まず④でプレイヤーBの「神の宣告」の無効化処理を行う。そのため⑤プレイヤーBの「神の宣告」の効果が無効になり、結果⑥「サンダーボルト」の効果が使える。
これをgitで例えると①の「サンダーボルト」の発動がファイルの変更をcommitした事実として、②〜⑤でrevertの対応をしている。
②の「神の宣告」でrevertを実施しようとしたところ、③④の「神の宣告」の発動と効果でrevertのrevertの処理が実行されるため、⑤の処理で②で発動した「神の宣告」の無効化処理が無効になったのである。
結果、⑥にて①でcommitした事実がそのまま実行される。
5。さいごに
gitのrevertをチェーンで理解したけど、結局はcommitに「〇〇をrevertした」とか「revertした〇〇をrevertした」とかのlogが延々と残るので、特定のcommitを復活させる必要がある場合など以外は基本的に使わない方が良さそう。
あとは、平行開発などでgitが何本も並行開発している時だと、場合によってはrevert時にコンフリクトを起こしそうなので、使うのは最小限の方がよさそう。
ついでにローカル開発でのgitのcommitの取り消しなら、普通に「git reset soft」や「git reset mixed」でやった方が良さそう(hardだと跡形もなく消えるけど、softやmixedならファイルの変更は残るし。)