21
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

分かった気になっていたgit reset --hardをちゃんと理解する

Last updated at Posted at 2022-03-31

git resetは学んだばかりのころは、「--hardをつけて間違った操作をすると実装が消えて戻らなくなる恐れがある」という印象が強く、実装を取り消す怖いコマンドのイメージでした。

使うのはたいてい以下のコマンドでしたが、どういうときに取り戻しがつかなくなるのかあまり分かっていなかったなと思います。

git reset --hard HEAD~

しかし別の使い方を見かけました。
例えば以下のようなツリーになっていて、branch1にいる時に、

git reset --hard branch2

とすると、以下のようにbranch2と同じcommitまで移動することができるということを知りました。
変更をリセットする(取り消す)コマンドだと思っていたので、git checkout branch2と何が違うのか、「リセット」と「commitの移動」にどう関係しているのかが分かっていませんでした。

このあたりについてresetコマンドを知ることが理解につながるので、resetについて説明していきます。
resetについては以下のドキュメントが分かりやすかったので、こちらを参考にまとめてみました。

正確な情報は上記のドキュメントを読んでください

補足: Gitのオブジェクト等について

以下ではHEADやcommitなどといったGitが扱っている、Gitオブジェクトやリファレンスなどがでてきますが、この記事で説明しようとすると大変なので、省略してざっくり理解できるように進めていきます。
知りたい方は個人的には以下の記事がとてもわかりやすかったです!

https://qiita.com/marchin_1989/items/2ec01553e907f3a9e6bb

またドキュメントも図解しながら説明されているので理解しやすかったです。

https://git-scm.com/book/ja/v2

3つのツリー

Gitで扱っているツリーという概念になぞらえて以下3つを挙げています。

image.png

端的に言うとこんな感じです。

  • HEAD → 最新のcommit
  • インデックス → git addしたステージングエリア
  • 作業ディレクトリ → 編集する実際のファイル

画像を引用しますが、以下のような流れで作業をしていきます。

ファイルを変更 → add → commit
image.png
image.png
image.png

以下はfile.txtに3回変更を加えた後の状態を示しています。

image.png

--soft

はじめに--softオプションから理解を深めます。
softはHEADを指定したところまで移動させますが、インデックスと作業ディレクトリは変更しません。

image.png

以下のように、Changes to be committedに緑色の文字でcommitした内容が存在しています。
そして、git logをすると、HEADが移動したことにより最終commitがfile.txt v2のコミットとなるので、3つ目のcommitが取り消されたように見えます。

$ git reset --soft HEAD~
$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   file.txt

インデックスと作業ディレクトリは変更されないため、編集したファイルの変更内容は取り消されずに残っています。

もとに戻す

さて、次のオプションも試したいので、file.txt v3のコミットまで戻りたいのですが、これもgit reset --softを使って戻すことができます。

前提として、file.txt v3のコミットハッシュを知っておく必要があるのですが、この例だと、以下のように実行することで、元に戻すことができます。

git reset --soft 38eb946

これも指定したコミットまでHEAD (とブランチ) を移動したことにより、元に戻った状態となります。

先程の、↓の画像の矢印が逆に動いたことになります。

image.png

--mixed (デフォルト)

さて、元に戻ったので、今度はmixedオプションを試します。
これはデフォルトなのでフラグがなくても同様の結果となります。

mixedオプションはHEADとインデックスの内容を変更します。

image.png

以下のように、Changes not staged for commitに赤色の文字でcommitした内容が存在しています。

$ git reset HEAD~
$ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   file.txt

作業ディレクトリは変更されないため、編集したファイルの変更内容は取り消されずに残っています。

最後のhardオプションを試したいので元に戻します。

git reset 38eb946

--hard

そして最後に今回の目的のhardです。
hardオプションは作業ディレクトリにも変更を加えます。

image.png

hardオプションを実行すると、作業ディレクトリも変更されるので、git statusをしても差分が表示されません。
そして手元のファイルを開いてみると、最後のコミットの変更内容がなかったことのように元に戻っています。

$ git reset --hard HEAD~
HEAD is now at 9e5e6a4 file.txt v2
$ git status
On branch main
nothing to commit, working tree clean

このように、変更された内容が消されてしまった状態になるので注意が必要です。

でも実際にはcommitが消されたわけではないので、今回の例だと、file.txt v3はcommitされており、ハッシュ値も分かっているので、前の例のように元に戻すことができます。

git reset --hard 38eb946

これで作業ディレクトリの内容も復元されます。

もとに戻せないケース

ただし、commitされていない状態だと元に戻すことができなくなります。例えば、

$ touch hoge.txt
$ git add hoge.txt
$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   hoge.txt

とcommitされていないと、

$ git reset --hard
$ git status
On branch main
nothing to commit, working tree clean

このように作業ディレクトリが上書きされて、変更自体がなくなってしまいます。

最初の例

git reset --hard branch2

最初の例の上記のコマンドに戻ります。以下の状態のように

branch1にいる時に 上記コマンドを実行すると、HEAD、インデックス、作業ディレクトリすべてがbranch2のコミットと同じものに書き換えられるため、git checkout branch2をしたときのように移動したかに見えました。

git checkout branch2と違う点

実はcheckoutとの違いとしては2点あります。

  1. 未保存の変更の扱い
    1. resetはチェックが行われずにすべてが上書きされる
    2. checkoutは未保存の変更をチェックして、作業ディレクトリを守ろうとする
  2. HEADの更新方法
    1. resetはブランチが移動
    2. checkoutはHEADが別ブランチに移動するだけで、branchは変更されない

このような違いを使い分ける必要があります。

21
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?