Git Reflog: Git でのリファレンスログの理解と使用

開発者やデータエンジニアにとって、意図せずにgitブランチを削除したり、コミットをリセットしたりすることほど迷惑なことはありません。だからこそ、私が自身の経験を通じて学び、もっと早く知っておきたかったことを共有できることを嬉しく思います。それは、git reflogの使い方です。git reflogは学ぶ価値のあるテクニックの一つであり、今少し時間を割けば、将来的に大きな頭痛を避けることができます。

私が非常に役立つと感じるgit reflogをお見せすることに加えて、バージョン管理について知っておくべきすべてを学ぶために、私たちのGitの基礎GitHubの概念入門のコースをお勧めしたいと思います。

git reflogとは何ですか?

Git reflog、またはリファレンスログは、Gitリポジトリ内のブランチの先端とHEADリファレンスへの更新を記録するローカルトラッキングメカニズムです。(Gitの文脈では、HEADは作業ディレクトリとステージングエリアが基づいている現在のコミットを指します。)

git logが先祖に基づいてコミット履歴を表示し、コミットがブランチでどのように接続されているかを示すのに対して、git reflogは、ブランチの切り替えやリベース、リセット、コミットを含むHEADのすべての動きをキャプチャします。これにより、reflogは失われたコミットを回復し、最近のアクションをデバッグするのに役立ちます。

reflogエントリはいつ作成されますか?

Reflogエントリは、HEADまたはブランチ参照の状態を変更するアクションを実行したときに作成されます。一般的なシナリオには、次のものがあります:

  • git commitを使用して変更をコミットする。

  • git checkout branch_nameを使用して異なるブランチにチェックアウトする。

  • git branch new_branchを使用して新しいブランチを作成する。

  • git rebaseを実行する

  • git reset --hardを使用して以前のコミットにリセットする。

  • git mergeを使用してブランチをマージする。

ローカルリポジトリの更新を追跡するために使用するコードは次のとおりです:

git reflog

ローカルリポジトリの更新を追跡するために git reflog を使用します。著者による画像。

git reflog の出力をどのように解釈しますか?

出力は次のように解釈できます:

  • HEAD@{0}: 最も最近のアクションは HEAD ブランチへの切り替えでした。

  • HEAD@{1}:その前に、ファイルの種類を.xlxsから.csv形式に変更しました。

  • HEAD@{2}:ファイルをリポジトリにプッシュする際に最初のコミットを作成しました。

各エントリには次の内容が表示されます:

  • コミットハッシュ(fa82776

  • リフログインデックス (HEAD@{0}, HEAD@{1} など)

  • 実行されたアクションの説明 (コミット、チェックアウト、リベース)

git reflogの使い方

Git reflogは、リファレンスの更新を追跡し、リポジトリの以前の状態を復元する方法を提供します。reflogエントリをナビゲートする方法を理解することで、失われたコミットを回復し、変更を元に戻し、作業の過去のバージョンを比較することができます。

基本的なgit reflogコマンド

以下は基本的なreflogコマンドです:

git reflog

上記のコマンドは、HEADやブランチリファレンスを更新する最近のアクションのリストを表示します。これには、コミット、ブランチの切り替え、リセット、リベースなどが含まれます。各エントリはインデックスされており、HEAD@{0}HEAD@{1}のように、reflog履歴内での位置を表します。

過去の状態を参照する

Git reflogは、過去の参照更新の記録として機能し、リポジトリの履歴の以前のポイントを特定して復元できるようにします。これがないと、これらの参照が存在せず、特定の過去の状態に戻るために正確なコミットハッシュが必要になります。それでは、Gitがどのようにしてgit checkoutを使用してこれらの過去の状態をナビゲートできるかを探ってみましょう。

HEAD@{n}:特定のreflogエントリを参照し、nはインデックスを表します。例えば、HEAD@{2}はHEADの3番目に新しい状態を指します。

git checkout HEAD@{2}

過去の変更を追跡するためにgit checkoutを使用する。著者による画像。

branch@{time}: 特定の時点でのブランチの状態を指します。例えば、main@{1.week.ago} は1週間前のmainブランチの状態を指し、feature@{yesterday} は昨日のfeatureブランチの状態を指します。

git checkout main@{1.week.ago}

過去の変更を追跡するためにgit checkoutを使用する。作者による画像。

時間ベースの修飾子

git reflog は過去の状態を復元するだけでなく、それらを比較するのにも役立ちます。 reflog は参照の更新を追跡するため、リポジトリが時間とともにどのように変化したかを確認するために使用できます。 では、git diff がreflogエントリを使用して過去と現在の状態を比較する方法を見てみましょう。

以下は、時間修飾子の例であり、reflogのインデックス番号だけに頼るのではなく、リポジトリを特定の時点に簡単に復元できるようにします。

git checkout HEAD@{1.minute.ago} # 1分前の状態
git checkout HEAD@{1.hour.ago} # 1時間前の状態
git checkout HEAD@{1.week.ago} # 1週間前の状態
git checkout HEAD@{yesterday} # 昨日の状態
git checkout HEAD@{2024-01-01.12:00:00} # 特定のタイムスタンプでの状態

過去の状態を git diff で比較する

過去の状態を git diff のようなコマンドを使用して比較できます。以下のコマンドは、メインブランチの現在の状態 main@{0} と1日前の状態 main@{1.day.ago} を比較します。出力は、これら2つのスナップショット間の違いを示します。

git diff main@{0} main@{1.day.ago}

過去の状態を git diff で比較する。著者による画像。

Git Reflog の一般的な使用例

Git reflog は、失われた変更を回復し、間違いを元に戻し、一般的な Git のトラブルを修正するための貴重なツールです。以下は、git reflog が役立つ実用的なシナリオです。

悪いリセットを元に戻す

もし git reset --hard を使ってブランチを誤ってリセットしてしまった場合、reflog を使用して以前の状態を復元できます。

git reset --hard HEAD@{3}

失われたコミットの回復

ブランチを間違って削除したり、リセットやリベースによってコミットが失われた場合、git reflogを使用して失われたコミットを見つけることができます。

git reflog

reflogの出力からコミットのハッシュを見つけ、それをチェックアウトします:

git checkout <commit-hash>

失われたコミットを確認したら、新しいブランチを作成して保存できます:

git branch recovered-branch <commit-hash>

ボッチしたリベースの修正

リベースが失敗した場合、git reflogを使用してリベース前のコミットを見つけ、ブランチをリセットできます。リベース前のコミットを特定してリセットしてください。

git reset --hard HEAD@{3} # reflogの出力に基づいて番号を調整してください

削除されたブランチの復元

ブランチを誤って削除した場合、git reflogを使用して復元できます。削除されたブランチの最後の既知のコミットを見つけて再作成してください:

git branch restored-branch <commit-hash>

スタッシュ履歴の追跡

Git reflogはスタッシュの履歴を表示するためにも使用できます。以下のコマンドはスタッシュ操作をリストし、必要に応じて古いスタッシュを復元できるようにします。

git reflog stash

以前のスタッシュエントリを適用するには、次のコマンドを使用します:

git stash apply stash@{2}

ローカルの変更を上書きするためのベストプラクティスを学ぶには、Git Pull Force: How to Overwrite a Local Branch With Remote チュートリアルをチェックしてください。

Git Reflogのサブコマンドとオプション

Gitは、リフログの管理および対話に使用できるいくつかのサブコマンドとオプションを提供しています。

Git reflogのサブコマンド

以下は、主要な git reflog サブコマンドとその使用方法の構造化された説明です。

git reflog show: デフォルトではHEADのリフログエントリを表示しますが、ブランチなどの指定されたリファレンス用のものも表示できます。

git reflog show

git reflog showを使用して指定されたリファレンスのエントリを表示します。著者による画像。

git reflog list:このコマンドはリファレンスごとのリファレンスログをすべて表示します。ブランチやHEADリファレンスに格納されたリファレンスログエントリを特定するのに便利です。

git reflog list

git reflog delete <ref>@{<specifier>}:指定された時間制限を超過する古いリファレンスログエントリを削除します。たとえば、次のコマンドは30日より古いエントリを削除します。

git reflog expire --expire=30.days.ago

git reflog delete <ref>@{<specifier>}:参照と位置に基づいて特定のリファレンスログエントリを削除します。以下のコマンドは、HEADのインデックス2にあるリファレンスログエントリを削除します。

git reflog delete HEAD@{2}

git reflog exists <ref>: 特定のリファレンスに対する reflog が存在するかどうかを確認します。たとえば、以下のコマンドはメインブランチに reflog がある場合に成功を返します。

git reflog exists main

git reflog サブコマンドのオプション

git reflog サブコマンドおよびその使用可能なオプションは以下の通りです。

--expire-unreachable=<time>: どのリファレンスからも到達不可能な reflog エントリのみを削除します。たとえば、以下のコマンドは7日より古い到達不能な reflog エントリを削除します。

git reflog expire --expire-unreachable=7.days.ago

--all: HEAD だけでなく、すべてのリファレンスの reflog を処理します。以下のコマンドはすべてのブランチで60日より古い reflog をクリーンアップします。

git reflog expire --expire=60.days.ago --all

--dry-run: コマンド実行をシミュレートし、実際には何も削除せずにプルーニングされる内容を表示します。例えば、以下のコマンドはどのエントリが削除されるかを示します。

git reflog expire --expire=30.days.ago --dry-run

--verbose: コマンドによって実行されたアクションの詳細な出力を提供します。以下のコマンドは古いリフログエントリを期限切れにする際に詳細情報を表示します。

git reflog expire --expire=90.days.ago --verbose

Git ReflogとGit Logの違い

git loggit reflogは、リポジトリの履歴に関する洞察を提供しますが、それぞれ異なる目的に使用されます。バージョン管理とリカバリ戦略のために各々がどのように使用されるかを理解するためにこれらの違いを見てみましょう。

  • git logは、ブランチ内のコミットの系譜をたどることでコミット履歴を表示します。リポジトリの内容がどのように進化したかの時間的な視点を提供します。

  • git reflogは、HEAD、ブランチ、スタッシュなどの参照の更新を記録し、ブランチの切り替え、リセット、リベースなどの操作を含みます。コミットの祖先に含まれない変更を追跡します。

  • git reflogは、厳密に言えば、あなたのマシンだけで利用され、リモートリポジトリとは共有されません。

  • git logはブランチ系譜の一部でなくなったコミットを回復することはできませんが、git reflogは、それらのコミットがもはやどのブランチからも到達できない場合でも、参照の更新を追跡することで「失われた」コミットを回復するのに役立ちます。

以下の表はこれらの主な違いをまとめています。

Feature git log git reflog
コミットを追跡する はい いいえ
参照の更新を追跡する いいえ はい
リモートで共有する はい いいえ
失われたコミットを復元できますか? いいえ はい

Git Reflogのベストプラクティス

Git reflogは失われたコミットを復元し、履歴の問題を修正するための強力なツールですが、効果的に使用するには注意が必要です。reflogを使用する際に従うべきベストプラクティスを以下に示します。

  • 復元とデバッグのためにReflogを使用する: ブランチを誤ってリセットまたはリベースした場合は、git reflogをチェックして以前の参照を見つけ、復元してください。

  • git reset –hardを注意して使用してください:git reset --hardはコミットされていない変更を永久に削除する可能性があります。何か問題が発生した場合に備えて、常に最初にreflogをチェックしてから実行してください。

  • 破壊的なコマンドを実行する前にバックアップを取ってください:データ損失を防ぐために、Gitリポジトリの自動バックアップを実装してください。常にバックアップを安全なオフサイトの場所に保存して、ハードウェアの障害やその他の災害が発生した場合にリカバリーできるようにしてください。

  • 長期的な復旧にはReflogだけに頼らないでください:デフォルトでは、reflogエントリは90日間保持されます。この期間が過ぎると、ガベージコレクションされて回復不可能になる可能性があります。ローカルのreflogを超えてコミットを定期的にリモートリポジトリにプッシュして、保存されることを確認してください。

  • git reflog expireを使用して古いエントリを管理する:リポジトリのリフログが混雑している場合は、git reflog expireを使用して古いまたは到達不可能なエントリを整理してください。

結論

Gitでプロジェクトの履歴を効果的に管理するには、基本的なコマンドだけでなく、参照更新を追跡する高度なツールを探索する必要があります。これにより、失われたコミットの回復、削除されたブランチの復元、ミスの修正に貴重な安全ネットを提供できます。これらのツールと、git resetgit checkoutgit revertなどのコマンドを実践的に使うことで、バージョン管理の能力が大幅に向上します。

当社のコースを受講することは学ぶだけでなく、ソフトウェア開発を真剣に考えていることを雇用主に示す素晴らしい方法です。そのため、私は、当社の すべてのレベル向けのトップ20 Git インタビューの質問と回答ブログ投稿を学習し、新しい Git基礎スキルトラックを受講して、Gitに関するすべてのことに精通したエキスパートになることをお勧めします。

Source:
https://www.datacamp.com/tutorial/git-reflog