復旧と安全

復旧と reflog

git が何かを失うことはめったにありません。難しいのは、それをもう一度見つけること です。

reflog

HEAD の — そして各ブランチの — あらゆる移動が、その原因つきで残ります。チェック アウト、リセット、リベース、amend、強制フェッチ。過去のどのエントリからでも、 チェックアウト したり、そこからブランチを作成 したり、そこへハードリセッ ト したりできます。

reflog ビューア

これが「間違ったブランチをリセットしてしまった」ときのボタンです。

WIP スナップショット

コミットしていない作業は reflog が救えない唯一のものです。そこで Gitcito はそれを スナップショットします。作業ツリー全体 — 変更済み・ステージ済み・未追跡のファイ ル — を使い捨てのインデックス経由でコミットし、refs/gitcito/wip の下に固定し ます。本物のインデックスにも、スタッシュ一覧にも、一切触れません。

WIP スナップショット

スナップショットを取るのは次の 3 つです。

トリガー タイミング
ガード 破壊的な操作 — 破棄、クリーン、ハードリセット、コミットからの復元 — の直前に自動で。既定で有効。スナップショットダイアログで切り替えられます。
タイマー リポジトリを開いている間、5 / 15 / 30 分ごとに。
手動 今すぐスナップショット ボタン。

いちばん重要なのはガードです。作業が永遠に失われるのは、たいてい意図しない破棄の 直後の一瞬だからです。ガードが有効なら、その状態はスナップショットとして残ってい ます — 一覧を開き、復元をクリックして、ひと息つきましょう。

スナップショットを選択すると、それが捉えたファイルを確認し、任意のファイルの変更 をプレビューして、ファイル 1 つだけ でもツリー全体でも復元できます。復元はス ナップショットからファイルを取り出して現在のコピーの上に書き写します — その前に ガードのスナップショットが取られるので、復元そのものも取り消せます。

知っておきたい制限。 タイマーやガードが動いた時点で新しいものが何もなければ、 何も記録されません。復元はファイルを上書き・再作成しますが、スナップショットの後 に作成したファイルを削除することはありません。無視されているファイルは捉えられま せん。スナップショットはローカルの隠れた ref です。プッシュされることはなく、 git gc からも安全で、新しい 50 件が保持されます。

ガイド付き bisect

コミットに問題あり / 問題なしの印を付け、範囲が狭まっていくのを見ながら、最初に 不具合が入ったコミットに着地します。Gitcito は残りのステップ数を追跡するので、答え まで質問 2 つなのか 10 なのかがわかります。

ガイド付き bisect

コマンドに判定させる

範囲の起点を与えたら、コマンドに判定させる で探索まるごとを git bisect run に 渡せます。git は候補を順にチェックアウトし、あなたのコマンドを実行して、その終了 コードを読みます。

終了コード 意味
0 問題なし — 不具合はここにはない
125 これはテストできない。スキップする
それ以外 問題あり

テストスイートはもともとその言語を話すので、たいていは npm test がそのまま答えに なります。Gitcito はこのプロジェクト自身のスクリプトをワンクリックで入力できるよう に提示し、実行中の出力をストリームし、あなたが 1 つも質問に答えないまま最初の不具 合コミットに着地します。

テストスイートに探索を渡す準備ができたコマンド欄

気をつけること。 コマンドは git がテストする すべての コミットで走るので、 デプロイしたり、公開したり、リポジトリの外に書き込んだりするコマンドは、それを何度 も繰り返します。読んで報告するだけのものに留めてください。停止 は実行を止めて セッションは開いたままにするので、続きは手で印を付けていけます。中止 は bisect そのものを終わらせます。

無関係な理由で失敗するコマンド — たとえば履歴のその時点では依存関係が欠けている、 といった場合 — は、問題のないコミットを問題ありと印を付け、探索を間違った場所へ導 きます。ラッパースクリプトから 125 で終了するのが、git の用意した逃げ道です。

残されたロックファイル

git は書き込もうとしているものの隣に .lock ファイルを置き、書き込みが終わると消します。 それを握ったまま死んだプロセス — 落ちたエディタ、git commit の途中で閉じられた ターミナル、リモート参照の刈り込み中に kill された fetch — はロックを残し、以後どの 書き込みも同じ行で失敗します:

error: could not delete references: cannot lock ref 'refs/remotes/origin/x':
Unable to create '…/refs/remotes/origin/x.lock': File exists.

リポジトリが壊れたわけではありません。ファイルが一つ道をふさいでいるだけです。

Gitcito はまず数回リトライします。動いている git が握るロックはたいていミリ秒で 解けるからです。それでも解けないときは、失敗が文字の壁ではなくダイアログを開きます。 ディスクに残っているロックの一覧、それぞれの経過時間、そしてそれらを削除して失敗した 操作をやり直すボタンです。

判断材料は経過時間がすべてです。 30 秒より新しいロックはまだ働いている git のものと みなし、Gitcito は削除を拒みます — 代わりに待って再試行することを勧めます。それより古い ものは古い順に削除候補として並び、同意する前に何を確かめるべきかをダイアログがはっきり 言います。いまこのリポジトリでエディタもターミナルも他の Git クライアントも作業していない こと。生きている書き込みの下からロックを抜くのが、インデックスが壊れる典型です。

走査はリポジトリ自身の git ディレクトリと共通ディレクトリを対象にするので、リンクされた worktree のロックも見つかります。サブモジュールは対象外です — あれは別のリポジトリのもので、 そちらを開けば片づきます。

取り消し / やり直し

ほとんどの操作は取り消しスタックにエントリを積むので、git が許す範囲で ⌘Z が直前の操作を巻き戻します。

関連項目: それ以降の変更 · スタッシュ

この翻訳を GitHub で改善