今日もエメラルド気分

1990年生まれ文系プログラマーの軌跡(予定)

【git】revertとresetの違い

revertとresetの違い

f:id:leokun0210:20171115004251p:plain

コミットを戻したい時にgit revertgit resetのどちらを使うか迷うyamakawa00です。

忘れないようにブログにまとめておきます。

前提条件 - commitができる。 - conflictが理解できる。

現在の状態

まずは、現在のブランチの状態です。

f:id:leokun0210:20171115000548p:plain

HEADがコミットハッシュ「4」にある状態です。

「3」にバグがあり、そのコミットを消したい状態です。




revert

1つ以上の既存のコミットがあれば、関連パッチが導入した変更を元に戻し、それらを記録する新しいコミットをいくつか記録します。これには、作業ツリーがきれいである必要があります(HEADコミットからの変更はありません)。

git公式リファレンスより

公式ドキュメントを見てもよくわかりませんね...

わかりやすく図にして見ました!

f:id:leokun0210:20171115001135p:plain

$ git revert [3のコミットハッシュ]

git revertとは、指定したコミットハッシュを打ち消すコミットを新たに行う行為をです。

上記の例では「3」のコミットを打ち消しています。

ただし基本的には、直前のコミット(つまりHEAD)を打ち消すために用いられます。

なぜ直前のコミットに適応するかというと、上記の図のように直前ではないコミットを打ち消すとコンフリクト(衝突)するからです。




revertのコンフリクト

「3」のコミットで「2」の変更点を消し、「4」のコミットで「3」の変更点を消すとどうなるでしょうか?

答えはコンフリクト(衝突)します。

実際にコンフリクトしたファイルは、こんな感じです。

diff --cc README.md
index 6a1769f,0c4a8b1..0000000
--- a/README.md
+++ b/README.md
@@@ -1,2 -1,2 +1,6 @@@
++<<<<<<< HEAD
 +4番目のcommit
++=======
+ 2番目のcommit
++>>>>>>> parent of 6c3bbd4... 3

コミットとは、コードの歴史を表すものです。

中学生の黒歴史を隠したいからといって、中学3年間を抹消すると、どこかで綻びが生じるので気をつけましょう。




reset

現在のHEADを指定された状態にリセットすることです。

ここでは、HEADを「2」に戻してみましょう。

f:id:leokun0210:20171115002253p:plain

$ git reset --hard [2のコミットハッシュ]

これで、HEADは「2」になっています。

「3」「4」は削除されます。

(厳密に言えば削除はされずに記録は残っています。ここから復元も可能です。)




reset --hardreset --soft

resetには--hard--softの二つのオプションが存在します。

$ git reset --hard [コミットハッシュ]
$ git reset --soft [コミットハッシュ]

--hardは、現在のファイルの状態をHEADの位置の指定コミットまで復元します。

--softは、現在のファイルは特に変更せずに、HEADの位置を指定コミットまで移動します。

つまり--softは強くてニューゲーム状態です




【まとめ】revertとresetの違い

最後に両者のメリット、デメリットをまとめてみます。

どちらを使えばいいかはケースバイケースでしょう。

コマンド メリット デメリット 使用ケース
revert コミットログ自体は残っているので、revertの取り消しが容易 基本的には、直前のコミットの打ち消ししかしない方が良い。なぜなら、コミットの整合性が取れなくなってしまうからである。 直前のコミットにバグがあるので消したい時
reset HEADの位置を大幅に移動できる。 以前のコミットを復元するのが少し手間 直前のコミットではないものにバグがある