🔖

Git で Ctrl+S を押すだけのクイックセーブを実現する

に公開

🎮 はじめに

Git で作業中、意図せず git clean で消してしまったり不要だと思って消した内容が後から必要になったりすることはありませんか? そんなときゲームのクイックセーブのように、Ctrl+S で現在の状態を記録しておけば、いざという時に過去のセーブポイントから復旧できます。

この記事では、Ctrl+S を押すだけで Git の作業状態をクイックセーブする仕組みを、zsh の設定で実装する方法を紹介します。

⚙️ 動作の仕組み

クイックセーブは次の3ステップで動作します

  1. すべての変更をステージング(git add --all
  2. タイムスタンプ付きのコミットを作成(git commit
  3. 作業ディレクトリをリセット(git reset HEAD~

変更をいったんすべてコミットし、git reset HEAD~ で作業ディレクトリを元の状態に戻します。実行後に見た目上は何も変わりませんが、コミット記録は reflog に残るため復元可能になります。

🛠️ 実装

zsh 関数の定義

.zshrc に以下の関数を追加します

# Git クイックセーブ関数
git_quicksave() {
  # タイムスタンプを生成
  local timestamp=$(date +%Y%m%d_%H%M%S)

  # 1. すべての変更をステージング
  # 2. タイムスタンプ付きのコミットを作成(フックはスキップ)
  # 3. 作業ディレクトリをリセット
  git add --all && \
  git commit -m "quicksave-${timestamp}" --no-verify && \
  git reset HEAD~
}

キーバインドの設定

Ctrl+S でクイックセーブを実行できるようにします

# ターミナルのフロー制御を無効化(Ctrl+S/Ctrl+Q を使えるようにする)
stty -ixon

# zle ウィジェットの定義
_zle_git_quicksave() {
  # コマンドラインが空の場合のみ実行
  if [[ -z "$BUFFER" ]]; then
    BUFFER="git_quicksave"
    zle accept-line
  fi
}

# ウィジェットを登録
zle -N _zle_git_quicksave

# Ctrl+S にバインド
bindkey '^s' _zle_git_quicksave

🔄 復旧方法

クイックセーブの確認

クイックセーブした記録は git reflog で確認できます

# reflog を確認
$ git reflog
3a5b7c9 HEAD@{0}: reset: moving to HEAD~
8f2d4e1 HEAD@{1}: commit: quicksave-20250315_142530 # <-クイックセーブ
3a5b7c9 HEAD@{2}: commit: 通常の作業コミット
# quicksaveのみリスト
$ git reflog --grep="quicksave"
8f2d4e1 HEAD@{1}: commit: quicksave-20250315_142530
2373e05 HEAD@{5}: commit: quicksave-20250315_120421
d12d67d HEAD@{9}: commit: quicksave-20250315_115439

復元方法の使い分け

全体を過去の状態に戻す(現在の変更は破棄)

# クイックセーブ時点に完全に戻る
git reset --hard HEAD@{1}

特定のファイルだけ取り出す(現在の変更は維持)

# 削除したファイルを復活させる
git checkout HEAD@{1} -- path/to/file.txt

# すべてのファイルを取り出す(現在のコミット位置は変わらない)
git checkout HEAD@{1} -- .

差分を確認してから決める

# 何が変わるか確認
git diff HEAD HEAD@{1}

📝 使用例

実際の開発フローでの使い方

# Ctrl+S を押してクイックセーブ実行
# 新規ファイル2つと変更1つが存在している状態
[main 4b0f5db] quicksave-20250815_092143
 3 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 debug.log
 create mode 100644 newfile.ts
Unstaged changes after reset:
M	README.md

# git cleanを実行して未トラックの新規ファイルを削除
# コミットしてないので通常は復元不能
$ git clean -fd
Removing debug.log
Removing newfile.ts

# やっぱり消したファイルが必要だった
# reflog で確認
$ git reflog
52e4f73 HEAD@{0}: reset: moving to HEAD~
4b0f5db HEAD@{1}: commit: quicksave-20250815_092143
52e4f73 HEAD@{2}: commit 通常の作業コミット

# HEAD@{1} から復元
$ git checkout HEAD@{1} -- newfile.ts
$ cat newfile.ts

𝑮𝒐𝒕 𝑲𝒐𝒕𝒐𝒏𝒂𝒌𝒊...

⚠️ 注意点

🔍 他の手法との比較

git stash との違い

git stash は作業の一時退避には便利ですが、クイックセーブとは性質が違い取り出すと消えます

クイックセーブ git stash
目的 チェックポイント作成 作業の一時退避
作業の継続 そのまま継続可能 pop/apply が必要
記録の永続性 reflog に30日間保持 pop すると消える
複数の保存 タイムスタンプで管理 スタック管理が煩雑

WIP コミットとの違い

WIP(Work In Progress)コミットを作る方法もありますが、reflogを使ったクイックセーブでは最終的なコミットログを意識しなくて済むという違いがあります

# WIP コミットの例
git add -A
git commit -m "WIP"

WIP コミットの場合

  • コミット履歴が汚れる
  • rebase や squash での整理が必要
  • push すると不要なファイルも共有されるが、リモートに保存できて安心

クイックセーブの場合

  • コミット履歴に残らない(reset するため)
  • 一時ファイル(ログ、テストスクリプト等)も気軽に保存
  • 最終的にコミットしないものも含められる
  • 履歴の整理が不要
  • あくまで一時的なローカルバックアップ。リモートに保存しないと失われるので必要なものはちゃんとコミットしてpushする

🎯 まとめ

zshのショートカットでGitにクイックセーブ機能を実装できました。Ctrl+S 一つで安心して実験的な変更に挑戦できるようになります。Git の reflog を活用することで、いつでも過去のセーブポイントに戻れる安全網を手に入れましょう。

Studio Tech Blog

Discussion