Git のリセットと reflog

GitGitBeginner
今すぐ練習

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

ようこそ、Gitのタイムトラベラー!今日は、Gitリポジトリの履歴を前例のない制御力を与える2つの強力なGit機能を探っていきましょう:git resetgit reflog。これらのツールは、Gitのタイムマシンの高度なコントロールに似ており、プロジェクトのさまざまな状態間を移動し、さらには「失われた」作業を復元することができます。

git reset コマンドは、変更を取り消し、ファイルをステージング解除し、コミット履歴を書き換えることさえできる多用途のツールです。しかし、大きな力には大きな責任が伴い、git reset は初心者にとって少々恐ろしいかもしれません。そこで登場するのが git reflog です - これは安全ネットの役割を果たし、リポジトリのrefs(ブランチの先端など)に対して行うすべての変更を追跡し、最激しいリセットでさえも回復できるようにします。

この実験では、以下の内容を扱います。

  1. ソフトリセット:作業ディレクトリやステージングエリアを変更せずにHEADを移動する
  2. ミックスリセット:作業ディレクトリの変更を保持しながら変更をステージング解除する
  3. ハードリセット:変更を完全に破棄する
  4. 破壊的な操作からの回復にreflogを使用する
  5. 時刻ベースのリセット:特定の時点の状態にリポジトリを移動する

この実験が終わるとき、これらの強力なGit機能を安全かつ効果的に使用する方法をしっかりと理解しているでしょう。必要なときにいつでも元に戻ることができることを知り、自信を持ってリポジトリの履歴を操作できるようになります。

さあ、一緒に git resetreflog をマスターし始めましょう!


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL git(("Git")) -.-> git/SetupandConfigGroup(["Setup and Config"]) git(("Git")) -.-> git/BasicOperationsGroup(["Basic Operations"]) git(("Git")) -.-> git/DataManagementGroup(["Data Management"]) git(("Git")) -.-> git/BranchManagementGroup(["Branch Management"]) git/SetupandConfigGroup -.-> git/init("Initialize Repo") git/BasicOperationsGroup -.-> git/status("Check Status") git/BasicOperationsGroup -.-> git/commit("Create Commit") git/DataManagementGroup -.-> git/reset("Undo Changes") git/BranchManagementGroup -.-> git/log("Show Commits") git/BranchManagementGroup -.-> git/reflog("Log Ref Changes") subgraph Lab Skills git/init -.-> lab-387491{{"Git のリセットと reflog"}} git/status -.-> lab-387491{{"Git のリセットと reflog"}} git/commit -.-> lab-387491{{"Git のリセットと reflog"}} git/reset -.-> lab-387491{{"Git のリセットと reflog"}} git/log -.-> lab-387491{{"Git のリセットと reflog"}} git/reflog -.-> lab-387491{{"Git のリセットと reflog"}} end

作業環境のセットアップ

resetreflog を始める前に、実験用のコミットを含む作業環境をセットアップしましょう。新しいディレクトリを作成し、Gitリポジトリを初期化し、複数のコミットを含むいくつかのファイルを追加します。

ターミナルを開き、次のコマンドを入力します。

cd ~/project
mkdir git-reset-lab
cd git-reset-lab
git init

次に、いくつかのファイルを作成し、一連のコミットを行います。以下のコマンドをターミナルにコピーして貼り付けます。

echo "## Git Reset and Reflog Lab" > README.md
git add README.md
git commit -m "Initial commit"

echo "function add(a, b) { return a + b; }" > math.js
git add math.js
git commit -m "Add addition function"

echo "function subtract(a, b) { return a - b; }" >> math.js
git add math.js
git commit -m "Add subtraction function"

echo "function multiply(a, b) { return a * b; }" >> math.js
git add math.js
git commit -m "Add multiplication function"

さっきやったことを分解してみましょう。

  1. READMEファイルを作成し、初期コミットを行いました。
  2. 加算関数を持つJavaScriptファイルを作成し、コミットしました。
  3. 同じファイルに減算関数を追加し、コミットしました。
  4. 最後に、乗算関数を追加してコミットしました。

これで、実験用の履歴を持つリポジトリができました!

ソフトリセット:HEADの移動

最初に調べるリセットの種類は「ソフト」リセットです。ソフトリセットは、HEAD(および現在のブランチ)を別のコミットに移動しますが、ステージングエリアや作業ディレクトリは変更しません。これは、いくつかのコミットを「取り消す」必要があるが、新しいコミットにすべての変更を保持したい場合に便利です。

ソフトリセットを試してみましょう。

git reset --soft HEAD~1

このコマンドは、HEADを1つ前のコミットに戻します。~1 は「現在のコミットの1つ前」を意味します。~2~3 などを使用して、複数のコミット前に戻ることもできます。

次に、git status を実行すると、最後のコミットの変更がステージングされ、再びコミットできる状態になっていることがわかります。作業ディレクトリ内のファイルは変更されていません。

これは、最後の数コミットを1つにまとめたいシナリオで便利です。いくつかのコミット前にソフトリセットしてから、それらの変更すべてを含む新しいコミットを作成することができます。

これらの変更を新しいメッセージで再びコミットしましょう。

git commit -m "Add subtraction and multiplication functions"

忘れないでください。ソフトリセットは一般的に安全です(変更を破棄しないため)が、履歴を書き換えます。元のコミットを既にプッシュしている場合、リモートブランチを更新するために強制プッシュする必要があり、これはコラボレータにとって問題を引き起こす可能性があります。共有履歴を書き換える前に、必ずチームと連絡を取ってください!

ミックスリセット:変更のステージング解除

次に見るリセットの種類は「ミックス」リセットです。これは、フラグを指定しない場合の git reset の既定のモードです。ミックスリセットは、HEADを移動し、ステージングエリアを更新して一致させますが、作業ディレクトリには触れません。

いくつかの変更を加えてステージングしましょう。

echo "function divide(a, b) { return a / b; }" >> math.js
git add math.js

次に、この変更をステージングしたくなくなったとしましょう。ミックスリセットを使用できます。

git reset HEAD

これにより、変更がステージング解除されますが、作業ディレクトリには残ります。この時点で git status を実行すると、math.js が変更されているが、ステージングされていないことがわかります。

ミックスリセットは、一部の変更をステージングした後で、まだコミットする準備ができていないと判断した場合に便利です。もしかすると、変更を再度確認したり、ステージングする前にさらに修正を加えたいかもしれません。

忘れないでください。ソフトリセットとは異なり、ミックスリセットはステージングエリアを変更します。ただし、作業を破棄することはなく、すべてがまだ作業ディレクトリにあるという意味では、依然として安全です。

ハードリセット:変更の破棄

3番目で最も激しいリセットの種類は「ハード」リセットです。ハードリセットは、HEADを移動し、ステージングエリアを更新し、作業ディレクトリも更新して一致させます。これは、リセット先のコミット以降のすべての変更を破棄することを意味します。

ハードリセットを試してみましょう。

git add math.js
git commit -m "Add division function"
git status
git reset --hard HEAD~1

これにより、除算関数をステージングしてコミットした後、前のコミットにハードリセットを行い、実質的に最後のコミットを「取り消し」して変更を破棄します。

math.js を見ると、除算関数が消えていることがわかります。まるで書いたことがなかったかのようです。

ハードリセットは強力ですが危険です。前のコミットから完全に新しく始めるためにいくつかの作業を完全に破棄したい場合に便利です。ただし、永久に変更を破棄できるので、非常に注意して使用してください。

ハードリセットを行う前に、必ず正しいコミットにリセットしているかどうかを再度確認してください。不確かな場合は、ソフトまたはミックスリセットを使用するか、実験する前に新しいブランチを作成する方が安全です。

失われたコミットを回復するためのreflogの使用

さて、もし除算関数を破棄するつもりでなかったことに気づいたらどうなるでしょうか。ここで git reflog が助けになります。reflogは、あなたのローカルリポジトリ内でHEADがあったすべての場所のログです。resetのような履歴を書き換えるコマンドさえ記録する、超履歴のようなものです。

reflogを見てみましょう。

git reflog

あなたが最近行ったすべての操作、resetも含めたリストが表示されるはずです。各エントリにはHEAD@{n}の識別子があります。

失われたコミットを回復するには、ハードリセットの前の状態にリセットできます。

git reset --hard HEAD@{1}

これは、最後の操作(ハードリセット)の前のHEADの状態にリセットします。

math.js を確認すると、除算関数が戻っているはずです!

cat math.js
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function multiply(a, b) { return a * b; }
function divide(a, b) { return a / b; }

reflogは強力なセーフティネットであり、ほとんどのGitの事故から回復することができます。ただし、それはあなたのマシンにローカルであり、一時的なものです(エントリは通常30日から90日間保持されます)。通常のバックアップや作業をリモートリポジトリにプッシュする代わりにはなりません。

時刻ベースのリセット

Gitはまた、特定の時点でリポジトリをその状態にリセットすることも可能です。おおよそ何時にリポジトリが戻したい状態にあったかを覚えている場合、これは便利です。

時刻ベースのリセットを試してみましょう。

git reset --hard master@{"1 hour ago"}

これにより、1時間前の状態にリポジトリをリセットします。「昨日」、「2日前」、「3分前」など、様々な時刻指定子を使用できます。

時刻ベースのリセットは、特定のコミットにリセットするよりも精度が低い場合があるので注意してください。時刻ベースのリセット後は常にリポジトリの状態を確認して、目的の場所に到達したことを確認してください。

忘れないでください。時刻ベースのリセットが期待通りの結果を得られなかった場合、常にreflogを使って時刻ベースのリセットを取り消すことができます。

まとめ

おめでとうございます、Gitのタイムロード!あなたはこれまでGitの最も強力で潜在的に危険なコマンドのいくつかをマスターしました。ここで扱った重要な概念を振り返りましょう。

  1. ソフトリセット:HEADを移動させるが、ステージングエリアや作業ディレクトリは変更しない。コミットをまとめるのに便利。
  2. ミックスリセット:HEADを移動させ、ステージングエリアを更新するが、作業ディレクトリには触れない。変更のステージング解除に最適。
  3. ハードリセット:HEADを移動させ、ステージングエリアを更新し、作業ディレクトリも更新する。強力だが、破壊的な可能性がある。
  4. reflog:HEADへのすべての変更を記録するセーフティネットで、ほとんどのGitの事故から回復できる。
  5. 時刻ベースのリセット:特定の時点でリポジトリをその状態にリセットできる。

大きな力には大きな責任が伴います。これらのコマンドは、リポジトリの履歴を信じられないほどコントロールできる一方で、不注意に使うと危険です。リセット、特にハードリセットを行う前に必ず再度確認し、もし何かが悪くなった場合にはreflogがあなたの味方であることを忘れないでください。

Gitの旅を続けるにあたり、これらのコマンドを安全な環境で練習して慣れるまで続けましょう。正しく使えば、これらは強力なツールで、Gitのワークフローを大幅に向上させることができます。

楽しいリセットを!そして、あなたのGitの履歴が常にクリーンで意味のあるものでありますように!