git reset コマンドは、変更を元に戻すための複合的で汎用性の高いツールです。3 つの主な形式で呼び出します。これらの形式は、コマンド ライン引数 --soft、--mixed、--hard に対応します。これら 3 つの引数はそれぞれ、Git の 3 つの内部状態管理メカニズムであるコミット ツリー (HEAD)、ステージング インデックス、作業ディレクトリに対応しています。

Git Reset と 3 つの Git ツリー

git reset の使い方を正しく理解するには、まず Git の内部状態管理システムを理解しておく必要があります。これらのメカニズムは、Git の「3 つのツリー」と呼ばれることがあります。従来のツリー型データ構造とは厳密には異なるため、ツリーという呼び方は必ずしも正確ではありません。しかし、編集のタイムラインを追跡する、ノードとポインターをベースにしたデータ構造になっているため、これらのメカニズムをわかりやすく説明するには、リポジトリにチェンジセットを作成して 3 つのツリーでたどっていくのが最適です。

まず初めに以下のコマンドで新しいリポジトリを作成します。

$ mkdir git_reset_test
$ cd git_reset_test/
$ git init .
Initialized empty Git repository in /git_reset_test/.git/
$ touch reset_lifecycle_file
$ git add reset_lifecycle_file
$ git commit -m"initial commit"
[main (root-commit) d386d86] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 reset_lifecycle_file

上のサンプル コードでは空のファイル reset_lifecycle_file を使用して新しい Git リポジトリを作成します。この時点で、サンプル リポジトリには reset_lifecycle_file を追加することによる 1 つのコミット (d386d86) があります。

作業ディレクトリ

最初に調べるツリーは「作業ディレクトリ」です。このツリーはローカルファイルシステムと同期しており、ファイルとディレクトリへの変更はこのツリーに即座に反映されます。


$ echo 'hello git reset' > reset_lifecycle_file
$ git status 
On branch main
Changes not staged for commit: 
(use "git add ..." to update what will be committed) 
(use "git checkout -- ..." to discard changes in working directory) 
modified: reset_lifecycle_file

デモ リポジトリでは、reset_lifecycle_file を修正してコンテンツを追加しています。git status を呼び出すと、ファイルへの変更を Git が認識していることがわかります。これらの変更は現在、1 つ目のツリーである「作業ディレクトリ」に属しています。git status を使って作業ディレクトリへの変更を表示できます。変更は「modified」のプレフィックスが付いた赤字で表示されます。

ステージングインデックス

次に「ステージング インデックス」ツリーを見ていきます。このツリーは、git add でプロモートされて後続のコミットに保存される作業ディレクトリの変更を追跡します。このツリーは、複雑な内部キャッシュ メカニズムです。Git では通常、ステージング インデックスの実装の詳細をユーザーから隠そうとします。

ステージング インデックスの状態を正確に表示するには、あまり知られていない git コマンド git ls-files を使用する必要があります 。git ls-files コマンドは、基本的にステージング インデックス ツリーの状態を検査するためのデバッグ ユーティリティです。

git ls-files -s
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0   reset_lifecycle_file

ここでは、-s または --stage オプションで git ls-files を実行しました。-s オプションを指定しない場合、git ls-files 出力にはインデックスに現在属しているファイル名とパスのリストだけが表示されます。-s オプションではステージング インデックスのファイルの追加メタデータが表示されます。このメタデータはステージされたコンテンツのモード ビット、オブジェクト名、ステージ番号です。ここでは 2 番目の値 (d7d77c1b04b5edd5acfc85de0b592449e5303770) であるオブジェクト名に注目します。これは標準の git オブジェクト SHA-1 ハッシュで、ファイルのコンテンツのハッシュです。コミット履歴にはコミットと ref へのポインターを識別するための独自のオブジェクト SHA ハッシュが保存されています。ステージング インデックスにはインデックス内のファイルのバージョンを追跡するための独自のオブジェクト SHA ハッシュがあります。

次に、修正した reset_lifecycle_file をステージング インデックスにプロモートします。


$ git add reset_lifecycle_file 

$ git status 

On branch main Changes to be committed: 

(use "git reset HEAD ..." to unstage) 

modified: reset_lifecycle_file

ここではステージング インデックスにファイルを追加する git add reset_lifecycle_file を呼び出しました。ここで git status を呼び出すと「コミットされる変更」の下に緑で reset_lifecycle_file が表示されます。git status は実際にはステージング インデックスを表していないため、注意が必要です。git status コマンドの出力には、コミット履歴とステージング インデックスの間の変更が表示されています。この時点のステージング インデックスのコンテンツを調べてみましょう。

 $ git ls-files -s 100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file

reset_lifecycle_file のオブジェクト SHA が e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 から d7d77c1b04b5edd5acfc85de0b592449e5303770 に更新されていることがわかります。

コミット履歴

最後のツリーは、コミット履歴です。git commit コマンドは、コミット履歴内にある永続的なスナップショットに変更を追加します。このスナップショットには、コミット時のステージング インデックスの状態も含まれます。

$ git commit -am"update content of reset_lifecycle_file"
[main dc67808] update content of reset_lifecycle_file
1 file changed, 1 insertion(+)
$ git status
On branch main
nothing to commit, working tree clean

ここでは、「resetlifecyclefile の内容を更新する」というメッセージで新しいコミットを作成しました。チェンジセットがコミット履歴に追加されました。この時点で git status を呼び出すと、ツリーには保留中の変更がないと表示されます。git log を実行すると、コミット履歴が表示されます。3 つのツリーに沿ってこのチェンジセットを追ってきたので、git reset の利用を開始できます。

仕組み

表面上は、git resetgit checkout と挙動が似ています。git checkoutHEAD ref ポインターのみを操作しますが、git resetHEAD ref ポインターと現在のブランチの ref ポインターを移動します。この挙動をわかりやすく説明するために、以下のサンプルを見てみてください。

4 つのノードで、「main ノード」が最後になっている

この例では、main ブランチの連続するコミットを詳しく見ていきました。現在、HEAD ref と main ブランチ ref はコミット d を指しています。それでは、git checkout bgit reset b の両方を実行して結果を比較してみましょう。

git checkout b

4 つのノードで、main が最後のノードを、head が 2 つ目のノードを指している

git checkout を実行しても、main ref は d を指したしたままです。HEAD ref が移動してコミット b を指しています。現在、このリポジトリは「detached HEAD」状態になっています。

git reset b

2 つのノードのセットが 2 つあり、head,main が最初のセットの 2 つ目のノードを指している

対照的に、git resetHEAD とブランチ ref の両方を指定したコミットに移動します。

git reset はコミットの ref ポインターを更新するだけでなく、3 つのツリーの状態を修正します。ref ポインターの修正は常に発生していて、3 番目のツリーであるコミット ツリーが更新されます。コマンド ライン引数 --soft、--mixed--hard でステージング インデックス ツリーと作業ディレクトリ ツリーの修正方法を指定します。

主なオプション

git reset のデフォルトの呼び出しには、--mixedHEAD の暗黙の引数があります。つまり、git reset を実行することは、git reset --mixed HEAD を実行しているのと同じことになります。このコマンド ラインで、HEAD は指定したコミットです。HEAD の代わりに、任意の Git SHA-1 コミット ハッシュも使用できます。

git のリセットのスコープ図

--hard

これは最も直接的かつ「危険」で使用頻度の高いオプションです。--hard を渡すと、コミット履歴の ref ポインターが指定したコミットに更新されます。その後、ステージング インデックスと作業ディレクトリは、指定したコミットの状態と同じになるようにリセットされます。ステージング インデックスと作業ディレクトリでこれまで保留されていたすべての変更は、コミット ツリーの状態と同じになるようにリセットされます。つまり、ステージング インデックスと作業ディレクトリで確定していないすべての保留中の変更が失われることになります。

これを実証するために、先ほど確立した 3 つのツリーのサンプル リポジトリを続けてみましょう。まず、リポジトリにいくつかの変更を加えましょう。サンプル リポジトリで次のコマンドを実行します。

$ echo 'new file content' > new_file
$ git add new_file
$ echo 'changed content' >> reset_lifecycle_file
 

これらのコマンドにより、new_file という名前の新しいファイルが作成され、リポジトリに追加されました。さらに、reset_lifecycle_file の内容が変更されます。これらの変更を適用し、git status を使用してリポジトリの状態を調べてみましょう。

$ git status
On branch main
Changes to be committed:
   (use "git reset HEAD ..." to unstage)

new file: new_file

Changes not staged for commit:
   (use "git add ..." to update what will be committed)
   (use "git checkout -- ..." to discard changes in working directory)

modified: reset_lifecycle_file

保留になっているリポジトリへの変更があることがわかります。ステージング インデックス ツリーには、new_file を追加するための保留中の変更があり、作業ディレクトリには reset_lifecycle_file を修正する保留中の変更があります。

次に進む前に、ステージング インデックスの状態も調べてみましょう。

$ git ls-files -s
100644 8e66654a5477b1bf4765946147c49509a431f963 0 new_file
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file

new_file がインデックスに追加されていることがわかります。reset_lifecycle_file を更新しましたが、ステージング インデックス SHA (d7d77c1b04b5edd5acfc85de0b592449e5303770) は変わっていません。ステージング インデックスにこれらの変更をプロモートするために git add を使用していないので、この挙動は予想通りです。これらの変更は作業ディレクトリに留まっています。

git reset --hard を実行して、リポジトリの新しい状態を調べましょう。

$ git reset --hard
HEAD is now at dc67808 update content of reset_lifecycle_file
$ git status
On branch main
nothing to commit, working tree clean
$ git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file

ここでは、--hard オプションを使って「ハード リセット」を実行しました。Git には、HEAD が最新のコミット dc67808 をポイントしていることを示す出力が表示されています。次は、git status を実行してリポジトリの状態を確認してみましょう。Git には保留中の変更がないことがわかります。ステージング インデックスの状態も調べると new_file が追加される前の時点にリセットされていることがわかります。reset_lifecycle_file に加えた変更と new_file の追加は失われたことになります。このようなデータの消失は元に戻せないという点を忘れないでください。

--mixed

デフォルトの操作モードで、ref ポインターが更新されます。ステージングインデックスは、指定したコミットの状態にリセットされます。ステージングインデックスで元に戻したすべての変更は作業ディレクトリに移動します。それでは実際にやってみましょう。

$ echo 'new file content' > new_file
$ git add new_file
$ echo 'append content' >> reset_lifecycle_file
$ git add reset_lifecycle_file
$ git status
On branch main
Changes to be committed:
    (use "git reset HEAD ..." to unstage)

new file: new_file
modified: reset_lifecycle_file


$ git ls-files -s
100644 8e66654a5477b1bf4765946147c49509a431f963 0 new_file
100644 7ab362db063f9e9426901092c00a3394b4bec53d 0 reset_lifecycle_file

上のサンプルではリポジトリにいくつか修正を加えました。ここでも、new_file を追加して reset_lifecycle_file のコンテンツを修正しています。これらの変更はその後、git add を使用してステージング インデックスに適用されます。リポジトリがこの状態になったので、リセットを実行してみましょう。

$ git reset --mixed
$ git status
On branch main
Changes not staged for commit:
    (use "git add ..." to update what will be committed)
    (use "git checkout -- ..." to discard changes in working directory)

modified: reset_lifecycle_file

Untracked files:
    (use "git add ..." to include in what will be committed)

new_file


no changes added to commit (use "git add" and/or "git commit -a")
$ git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file

ここでは「混合リセット」を実行しました。繰り返しになりますが、--mixed はデフォルトのモードで、git reset 実行時と同じ結果が得られます。git statusgit ls-files の出力を調べてみると、インデックス内に reset_lifecycle_file のファイルしかない状態に、ステージング インデックスがリセットされていることがわかります。reset_lifecycle_file のオブジェクト SHA が以前のバージョンにリセットされています。

ここで重要なのは、git status によって、reset_lifecycle_file に修正が入っていることと、追跡対象外ファイル new_file があることがわかったことです。これは明示的な --mixed の明示的な挙動です。ステージング インデックスがリセットされて、保留中の変更が作業ディレクトリに移動されました。対照的に、--hard を使ったリセットのケースではステージング インデックスと作業ディレクトリの両方がリセットされて更新が失われていました。

--soft

--soft 引数が渡されると、ref ポインターが更新されてそこでリセットが停止します。ステージング インデックスと作業ディレクトリは変更されません。この挙動をわかりやすく説明するのは簡単ではありません。引き続きデモ用リポジトリを使ってソフト リセットの準備を行いましょう。


$ git add reset_lifecycle_file 

$ git ls-files -s 

100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file 

$ git status 

On branch main

Changes to be committed: 

(use "git reset HEAD ..." to unstage) 

modified: reset_lifecycle_file 

Untracked files: 

(use "git add ..." to include in what will be committed) 

new_file

ここでも git add を使って、修正した reset_lifecycle_file をステージング インデックスにプロモートしました。インデックスが git ls-files の出力で更新されているのがわかります。git status の出力には「コミットされる変更」が緑で表示されています。前のサンプルの new_file が、追跡対象外ファイルとして作業ディレクトリで未確定状態になっています。以降のサンプルでは不要なので、rm new_file を実行してこのファイルを削除しましょう。

リポジトリがこの状態になったので、ソフト リセットを実行してみましょう。

$ git reset --soft
$ git status
On branch main
Changes to be committed:
    (use "git reset HEAD ..." to unstage)

modified: reset_lifecycle_file
$ git ls-files -s
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file

「ソフト リセット」を実行しました。git statusgit ls-files を実行してリポジトリの状態を確認すると、何も変更されていないことがわかります。これは想定された挙動です。ソフト リセットではコミット履歴だけがリセットされます。デフォルトでは、git resetHEAD とともにターゲット コミットとして呼び出されます。今回のコミット履歴はすでに HEAD にあるため、HEAD に暗黙的にリセットしても実際には何も起こりません。

--soft の理解を深めてうまく使えるようになるために、HEAD ではないターゲット コミットを用意する必要があります。ステージング インデックスには reset_lifecycle_file があるので、新しいコミットを作成してみましょう。

$ git commit -m"prepend content to reset_lifecycle_file"

この時点で、リポジトリには 3 つのコミットがあるはずです。1 つ目のコミットまで時間をさかのぼりましょう。これを行うには 1 つ目のコミットの ID が必要です。git log の出力を見ると ID がわかります。

$ git log
commit 62e793f6941c7e0d4ad9a1345a175fe8f45cb9df
Author: bitbucket 
Date: Fri Dec 1 15:03:07 2017 -0800
prepend content to reset_lifecycle_file

commit dc67808a6da9f0dec51ed16d3d8823f28e1a72a
Author: bitbucket 
Date: Fri Dec 1 10:21:57 2017 -0800

update content of reset_lifecycle_file

commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4

Author: bitbucket 
Date: Thu Nov 30 16:50:39 2017 -0800

initial commit

コミット履歴 ID は各システムで固有だということを覚えておきましょう。つまり、このサンプルのコミット ID と、ご自身のコンピューターに表示されているコミット ID は異なっているということです。このサンプルで使うコミット ID は 780411da3b47117270c0e3a8d5dcfd11d28d04a4 です。これが「最初のコミット」に対応する ID です。ID がわかったらそれを対象として指定してソフト リセットを実行します。

復習する前に、まずはリポジトリの現在の状態を確認しておきましょう。

$ git status && git ls-files -s
On branch main
nothing to commit, working tree clean
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file

ここでは git statusgit ls-files -s の連携コマンドを実行しました。これで、リポジトリとステージング インデックスの reset_lifecycle_file に保留中の変更があり、そのバージョンが 67cc52710639e5da6b515416fd779d0741e3762e であることがわかりました。これを忘れないようにしながら 1 つ目のコミットに戻ってソフト リセットを実行しましょう。

$git reset --soft 780411da3b47117270c0e3a8d5dcfd11d28d04a4
$ git status && git ls-files -s
On branch main
Changes to be committed:
    (use "git reset HEAD ..." to unstage)

modified: reset_lifecycle_file
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file

上のコードでは「ソフト リセット」を実行するとともに、リポジトリの状態を出力する git statusgit ls-files の連携コマンドも呼び出しています。リポジトリの状態の出力を調べるといくつか注目すべき点があります。まず、git status を見ると、reset_lifecycle_file が修正されたことがわかり、それらの修正が後続のコミット用にステージされた変更であることが強調表示されています。次に git ls-files の入力を見ると、ステージング インデックスは変更されておらず、前からあった SHA 67cc52710639e5da6b515416fd779d0741e3762e がそのままになっていることがわかります。

このリセットによって何が起こったのかをさらに詳しく見るために、git log を調べてみましょう。

$ git log commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4 Author: bitbucket  Date: Thu Nov 30 16:50:39 2017 -0800 initial commit

ログの出力を見ると、コミット履歴に 1 つだけコミットがあることがわかります。これによって、--soft で何が起きたかがわかりやすくなります。すべての git reset の呼び出しと同様に、リセットで行われる最初の処理はコミット ツリーのリセットです。以前の --hard--mixed のサンプルでは両方とも HEAD をポイントしておらず、コミット ツリーを過去の状態に戻していませんでした。ソフト リセット中に起こるのはこれがすべてです。

そうなると、git status の結果で修正されたファイルがあった理由がよくわからなくなります。--soft ではステージング インデックスを操作しないため、コミット履歴をたどってステージング インデックスが更新されたことになります。git ls-files-s の出力を見ると reset_lifecycle_file の SHA が変更されていないため、これは間違いありません。本来はツリー間の差分を表示するためのコマンドである git status は「3 つのツリー」の状態を表示しない点をここで繰り返しておきます。このサンプルでは、ステージング インデックスがコミット履歴よりも先の変更になっていてあたかもすでにそれらをステージしたかのような状態になっています。

取消しと打消し

git revert が変更を元に戻す「安全」な手段だとすると、git reset は危険な手法という考え方もできます。git reset には作業を失ってしまうという現実的なリスクがあります。git reset でコミットが削除されることはありませんが、コミットが「孤立」して ref からそのコミットに直接アクセスするパスがなくなることになります。孤立したコミットは通常、git reflog を使って特定、復元できます。git では内部ガベージ コレクターが実行されると孤立したコミットが完全に削除されます。git のデフォルトでは、30 日ごとにガベージ コレクターが実行されるように設定されています。コミット履歴は「git の 3 つのツリー」の 1 つです。残りの 2 つであるステージング インデックスと作業ディレクトリはコミットとは違って永続的なものではありません。作業を失ってしまう可能性のある唯一の git コマンドであるため、git reset の使用には細心の注意が必要です。

一方、打ち消しは公開済みコミットを元に戻すための安全な方法です。git reset ではステージング インデックスと作業ディレクトリへのローカルの変更を元に戻します。これら 2 つのコマンドの目的には明確な差があり、実装のされ方も異なっています。取り消しではチェンジセットが完全に削除されるのに対して、打ち消しでは元のチェンジセットが保持されたまま、新しいコミットを作成して元に戻す操作が行われます。

公開済み履歴の取り消しは厳禁

の実行後に一度でもスナップショットを公開リポジトリにプッシュした場合は、git reset コマンドを絶対に使用しないでください。コミットを公開したら、他の開発者がそれを前提として作業を行っていると考える必要があります。

他の開発者が開発中に行ったコミットを取り消すと、コラボレーションで深刻な問題が生じます。他の開発者があなたのリポジトリと同期しようとすると、プロジェクト履歴のある範囲が欠落したように見えます。公開済みのコミットを取り消すと何が起こるかを、以下の一連の図に示します。ここで origin/main ブランチは、ローカルな main ブランチに対応する中央リポジトリのブランチです。

ノードの 4 つのセットで、origin/main が最後の 1 つを指している

取り消した直後に新しいコミットを追加すると Git ではローカルな履歴が origin/main から分岐したと扱われて、リポジトリを同期するために必要なマージ コミットが他の開発者に対する混乱と作業妨害を引き起こす可能性があります。

重要なことは、git reset を使用する際には、結果が思わしくなかったローカルな実験的開発作業を取り消すことが目的であって、公開済みの変更の取り消しをしようとしてはならないと認識することです。公開済みのコミットを訂正する必要がある場合は、その目的の専用コマンド git revert が用意されています。

 git reset 

作業ディレクトリに何の変更も加えずに、指定したファイルをステージングエリアから削除するコマンドです。このコマンドを実行すると、変更を書き込むことなく指定したファイルをアンステージします。

 Git のリセット

作業ディレクトリに何の変更も加えることなく、ステージング エリアをリセットして直前のコミット時の状態と一致させるコマンドです。このコマンドを実行すると、変更を書き込むことなくすべてのファイルをアンステージし、一度ステージされたスナップショットを初めから再構築できるようになります。

 git reset --hard

ステージング エリアと作業ディレクトリをリセットして直前のコミット時の状態と一致させるコマンドです。--hard は、変更をアンステージした上でさらに作業ディレクトリ内のすべての変更を元に戻すことを Git に指示するフラグです。言い換えると、これはコミット前のすべての変更を全くなかったものとするコマンドであり、これを使用する場合はローカル マシン上で行った開発作業を本当に破棄していいのか否かを確認する必要があります。

 git reset  

現在のブランチの先端を commit の位置に戻した上でステージング エリアをその状態と一致するように元に戻しますが、作業ディレクトリのみはそのままにしておきます。 の実行後に行われた変更は作業ディレクトリに保存されており、より変更規模が小さくて整理されたスナップショットを作成してプロジェクト履歴の再コミットを行えます。

 git reset --hard  

現在のブランチの先端を commit の位置に戻した上でステージング エリアと作業ディレクトリをその状態と一致するように元に戻します。このコマンドを実行すると、コミット前の変更に加えてコミット後に行われたすべてのコミットも全くなかったものとなります。

ファイルのアンステージ

git reset コマンドはステージされたスナップショットを作成する際によく使われます。次の例では、hello.pymain.py の 2 個のファイルをリポジトリにすでに追加しているものと仮定しています。

# Edit both hello.py and main.py

# Stage everything in the current directory
git add .

# Realize that the changes in hello.py and main.py
# should be committed in different snapshots

# Unstage main.py
git reset main.py

# Commit only hello.py
git commit -m "Make some changes to hello.py"

# Commit main.py in a separate snapshot
git add main.py
git commit -m "Edit main.py"

ご覧のように、git reset を使用することにより次回のコミットと無関係な変更をアンステージし、そのコミットの目的を明確化できます。

ローカルなコミットの削除

次の例はより高度なユースケースを示します。ここでは実験的開発をしばらく行っていると仮定し、いくつかのスナップショットをコミットした後でそれらをすべて破棄する場合にどうするべきかを示します。

# Create a new file called `foo.py` and add some code to it

# Commit it to the project history
git add foo.py
git commit -m "Start developing a crazy feature"

# Edit `foo.py` again and change some other tracked files, too

# Commit another snapshot
git commit -a -m "Continue my crazy feature"

# Decide to scrap the feature and remove the associated commits
git reset --hard HEAD~2

git reset HEAD~2 コマンドは、現在のブランチをコミット 2 回分だけ前に戻すコマンドであり、実質的には最近作成した二つのスナップショットをプロジェクト履歴から削除する働きをします。以前に説明したように、このような reset コマンドの使用対象は未公開のコミットに限るべきです。すでに共有リポジトリにコミットをプッシュしている場合には決して上記の操作を行ってはなりません。

概要

git reset は、git リポジトリの状態に対するローカルの変更を元に戻すための強力なコマンドであることがわかりました。git reset を「git の 3 つのツリー」で操作しました。これらのツリーは、コミット履歴 (HEAD)、ステージング インデックス、作業ディレクトリです。これら 3 つのツリーに対応する 3 つのコマンド ライン オプションがあります。オプション --soft、--mixed--hardgit reset に渡せます。

この記事では、他にもいくつかの git コマンドを活用して取り消しプロセスをわかりやすく説明しました。各コマンドの詳細については、git statusgit loggit addgit checkoutgit refloggit revert の各ページを参照してください。

git reset を学ぶ準備はできていますか?

この対話式チュートリアルを利用しましょう。

今すぐ始める