Git 応用コマンド集 — rebase / bisect / reflog ほか 60+ コマンドを 9 カテゴリで

現場の Git は「日常 add/commit/push」だけで回るわけではなく、レビュー対応で履歴を整える rebase -i、 バグ混入版を二分探索する bisect、過去の状態に戻る reflog、複数ブランチ並行作業の worktree など、 応用コマンドを使えるかどうかで生産性が桁違いになります。

本記事は「日常 git は知っている」を前提に、現場でよく使う 60+ コマンドを 9 カテゴリに分けて深掘りします。 ハマりどころとリカバリ手順も併記。最後に「よく使うレシピ」も。

破壊的操作の前に必ず:
  • git status で commit 漏れがないか確認
  • git stash でローカル変更を退避(必要なら)
  • git branch backup-$(date +%s) で念の為のバックアップ参照を作る
  • 共有ブランチ(main/develop)への push --force は基本禁止 → --force-with-lease を使う

目次

  1. 履歴閲覧の応用 (log / show)
  2. 差分・ブレーム (diff / blame)
  3. ブランチ・タグ操作
  4. rebase — 履歴の整形
  5. cherry-pick / revert
  6. stash — 一時退避
  7. reflog / reset / restore — リカバリ系
  8. bisect — バグ二分探索
  9. worktree / submodule / hooks
  10. よく使うレシピ
  11. 用語集

1. 履歴閲覧の応用 (log / show)

git log — 履歴の見方を覚えると速い

# コンパクトに 1 行
git log --oneline

# グラフ + ブランチ構造
git log --oneline --graph --all --decorate

# 著者・期間絞り込み
git log --author='iigtn' --since='1 week ago' --until='today'
git log --since='2026-04-01' --until='2026-04-30'

# ファイル単位の履歴
git log --oneline -- path/to/file
git log -p -- path/to/file       # ファイルへの差分付き
git log --follow -- path/to/file # リネーム前まで追跡

# コミットメッセージ検索
git log --grep='fix' -i

# 変更内容(パッチ内容)の検索 — 「ある関数名がいつ消えたか」
git log -S 'function_name'       # 文字列出現の差し引き履歴
git log -G 'regex_pattern'       # 正規表現

# フォーマットカスタム
git log --pretty=format:'%h %an %ad %s' --date=short

# ファイルの変更行数統計
git log --stat -- path/to/file
git log --shortstat --since='1 month ago' | grep -E 'fil(e|es) changed'

git show — コミット詳細

git show HEAD                     # 最新コミットの内容
git show abc1234                  # 特定コミット
git show abc1234 -- path/file     # そのコミットでの特定ファイルの差分
git show abc1234:path/file        # そのコミット時点のファイル全体(取り出せる)
git show --stat HEAD              # 統計のみ
git show --name-only HEAD         # 変更ファイル名のみ

git shortlog — 著者別サマリ

git shortlog -sn                  # 著者ごとのコミット数(ランキング)
git shortlog -sn --since='1 month ago'
git shortlog --no-merges -sn      # マージコミット除外

2. 差分・ブレーム (diff / blame)

git diff — 変更差分

git diff                          # ワークツリー vs インデックス
git diff --staged                 # インデックス vs HEAD(commit 直前の最終確認)
git diff HEAD                     # ワークツリー vs HEAD
git diff main feature             # ブランチ間
git diff main..feature            # 同上
git diff main...feature           # main から枝分かれした共通祖先 vs feature
git diff abc123 def456            # 任意コミット間
git diff --stat                   # 統計のみ
git diff --name-only              # ファイル名のみ
git diff -w                       # 空白差分を無視
git diff --word-diff              # 単語単位の差分(文章編集に便利)

# 特定ファイルだけ
git diff -- path/to/file
git diff main feature -- path/to/file

# パッチとして保存
git diff main feature > my.patch
git apply my.patch                # 別の場所で適用

git blame — 行単位の責任者・時刻

git blame path/to/file
git blame -L 10,30 path/to/file       # 10〜30 行目だけ
git blame -w path/to/file             # 空白変更を無視
git blame -C path/to/file             # コピー / 移動も追跡
git blame --since='6 months ago' file # 期間内の変更だけ

# 特定行が「いつから」あるか
git log -L 10,30:path/to/file
コードレビュー中・障害調査中に「この行いつ・なぜ入った?」で git blame → コミットハッシュ → git show で コミットメッセージ・PR 番号を辿るのが現場の鉄板コンボ。

3. ブランチ・タグ操作

ブランチ管理

git branch                          # ローカルブランチ一覧
git branch -a                       # リモート含む
git branch -vv                      # 追跡先 + 最終コミット表示
git branch --merged main            # main にマージ済みのブランチ
git branch --no-merged main         # まだマージされてないブランチ

git switch -c feature/new           # 新規ブランチ + 切替(推奨、checkout より明確)
git switch main                     # 既存ブランチへ切替
git switch -                        # 直前のブランチに戻る

git branch -m old-name new-name     # ローカル名変更
git branch -d topic                 # 削除(マージ済み必須)
git branch -D topic                 # 強制削除

git push origin --delete topic      # リモート側削除
git fetch -p                        # 削除済みリモート参照のクリーンアップ

追跡ブランチ

git branch -u origin/main           # 現ブランチの追跡先設定
git branch --unset-upstream         # 追跡解除
git push -u origin feature          # push と同時に追跡先を作る

タグ

git tag                             # タグ一覧
git tag v1.2.3                      # 軽量タグ
git tag -a v1.2.3 -m 'release 1.2.3'    # 注釈付き(推奨)
git tag -a v1.2.3 abc123 -m '...'   # 過去コミットにタグ
git push origin v1.2.3              # 1 個 push
git push origin --tags              # 全タグ push
git tag -d v1.2.3                   # ローカル削除
git push origin :refs/tags/v1.2.3   # リモート削除

4. rebase — 履歴の整形

レビュー指摘で「コミットを 1 つにまとめて」「メッセージ修正して」と言われた時の道具。 リモートに push 済みのブランチを書き換える時は --force-with-lease 必須。

非対話 rebase

# 自分のブランチを最新 main の上に乗せ直す(PR 前の定番)
git switch feature
git fetch origin
git rebase origin/main

# あるいはまとめて
git pull --rebase origin main

# rebase 中の競合解決
# 1. 競合ファイルを編集
# 2. git add <file>
# 3. git rebase --continue
# 中断したい
git rebase --abort
# このコミットを飛ばす
git rebase --skip

対話 rebase (-i) — squash / reword / drop

git rebase -i HEAD~5             # 直近 5 コミットを編集
git rebase -i abc123              # abc123 の次のコミットから編集
git rebase -i --root              # 全履歴を編集(最初のコミットから)

# エディタが開く。各行のキーワードを書き換える:
#   pick   = そのまま使う
#   reword = メッセージだけ書き直す
#   edit   = 一旦止めて中身を直してから git rebase --continue
#   squash = 直前のコミットに統合(メッセージは結合)
#   fixup  = squash と同じだがメッセージ捨てる
#   drop   = コミットを消す
git push --force は他人の commit を吹き飛ばす危険あり。代わりに --force-with-lease を使えば、 自分が把握していないリモート更新がある場合に push が失敗してくれる。

rebase --onto — 起点の付け替え

# A → B → C の C を B の上ではなく D の上に乗せ直す
git rebase --onto D B C

# よくあるシナリオ: 親ブランチが消えた後の救済
git rebase --onto main old-base feature

5. cherry-pick / revert

cherry-pick — 別ブランチのコミットを持ってくる

git cherry-pick abc1234              # 1 コミット持ってくる
git cherry-pick abc1234 def5678      # 複数
git cherry-pick A..B                 # A〜B の範囲(A は含まない、B は含む)
git cherry-pick A^..B                # A も含む

git cherry-pick -x abc1234           # コミットメッセージに「(cherry picked from ...)」追加
git cherry-pick -n abc1234           # コミットせず内容のみ取り込む(複数まとめてコミットしたい時)

# 競合時
git cherry-pick --continue
git cherry-pick --abort
git cherry-pick --skip

revert — 過去コミットを打ち消す新コミット

git revert abc1234                   # 打ち消しコミットを作る(履歴は残る)
git revert HEAD                      # 最新を打ち消す
git revert -n abc1234                # コミットせず内容のみ revert(複数まとめて)
git revert abc1234..def5678          # 範囲(古い順 to 新しい順)

# マージコミットを revert(親番号の指定が必要)
git revert -m 1 <merge_commit>

6. stash — 一時退避

git stash                            # ワークツリーとインデックスを退避(追跡ファイルのみ)
git stash -u                         # 未追跡ファイルも含む
git stash -a                         # 未追跡 + 無視ファイルも全部
git stash push -m 'msg'              # メッセージ付き
git stash push path/to/file          # 特定ファイルだけ stash

git stash list                       # スタッシュ一覧
git stash show stash@{0}             # 中身(統計)
git stash show -p stash@{0}          # 中身(差分)

git stash pop                        # 最新の stash を取り出して削除
git stash apply stash@{1}            # 取り出すが削除しない
git stash drop stash@{0}             # 削除
git stash clear                      # 全削除

# 別ブランチに stash を適用
git stash branch new-branch stash@{0}
stash pop 時に競合すると stash は 削除されない(apply 失敗扱い)。安心して再試行できる。

7. reflog / reset / restore — リカバリ系

reflog — Git 内部の操作履歴(最強の救命綱)

commit / checkout / rebase / reset すべての HEAD 移動が記録されている。「やらかした」時の復旧の起点

git reflog                           # 操作履歴
git reflog show feature               # 特定ブランチの reflog

# 「reset --hard したけど元に戻したい」
git reflog                            # 戻したい状態の SHA や HEAD@{N} を確認
git reset --hard HEAD@{2}             # 2 つ前の状態に戻す

reset — HEAD・インデックス・ワークツリーの巻き戻し

モードHEADインデックスワークツリー
--soft移動変えない変えない
--mixed (デフォルト)移動HEAD に合わせる変えない
--hard移動HEAD に合わせるHEAD に合わせる(破壊)
git reset --soft HEAD~1              # 直前コミットを取り消すが変更は残す(再コミット用)
git reset HEAD path/to/file          # ステージング解除
git reset --mixed HEAD~1             # 直前コミット取り消し + アンステージ
git reset --hard origin/main         # ブランチをリモートに完全に合わせる(ローカル変更は消える)

restore — ファイル単位の取り消し(git 2.23+ 推奨)

git restore path/to/file             # ワークツリーを HEAD に戻す(変更破棄)
git restore --staged path/to/file    # アンステージ(reset HEAD と同じ)
git restore --source=abc123 path     # 特定コミットの状態に戻す
git restore --source=HEAD~3 .        # 全ファイルを 3 コミット前に戻す

checkout の代替ツリー(参考)

git switch branch                    # ブランチ切替(旧 git checkout branch)
git restore file                     # ファイル復元(旧 git checkout -- file)
git restore --staged file            # アンステージ(旧 git reset HEAD file)

8. bisect — バグ二分探索

「最近壊れた、原因コミットを特定したい」時の最強ツール。 古い良いコミット (good) と新しい壊れたコミット (bad) を指定すると、Git が二分探索して原因を絞り込む。

手動 bisect

git bisect start
git bisect bad                       # 現在 (HEAD) は壊れている
git bisect good v1.0.0               # v1.0.0 は動いていた

# Git が中間コミットに切り替えてくれる
# テストして良し悪しを伝える
git bisect good          # OK だった
# or
git bisect bad           # NG だった

# 繰り返すと "abc123 is the first bad commit" と特定される

git bisect reset         # 終了して元の HEAD に戻す

自動 bisect

# テストスクリプトの exit code で自動判定
# 0 = good, 1〜127 (125 除く) = bad, 125 = skip
git bisect start HEAD v1.0.0
git bisect run npm test

# CLI 1 行で良し悪し判定できるなら超強力
git bisect run sh -c 'curl -sf http://localhost:8080/health'

9. worktree / submodule / hooks

worktree — 同じリポジトリで複数ブランチを並行作業

git worktree add ../proj-fix hotfix/login    # hotfix ブランチを別ディレクトリに展開
git worktree add -b new ../proj-new main     # 新規ブランチを作って add
git worktree list                            # 作業ツリー一覧
git worktree remove ../proj-fix              # 削除
git worktree prune                           # 消えた作業ツリーの参照を整理
stash で行ったり来たりする代わりに worktree add。レビュー対応中・hotfix と機能開発を完全分離したい時に最適。

submodule — リポジトリ内に別リポジトリを取り込む

git submodule add git@github.com:org/lib.git lib
git submodule init
git submodule update                # サブモジュール側を初期化 + checkout
git submodule update --init --recursive    # 再帰、初回 clone 後に頻出

# 全サブモジュールを最新に
git submodule update --remote --merge

# 状態確認
git submodule status

# 削除(やや面倒)
git submodule deinit -f lib
git rm -f lib
rm -rf .git/modules/lib
submodule の運用は複雑。代替として git subtreemonorepo 化、または npm/pip パッケージ化を先に検討。

hooks — クライアント側の自動化

# プロジェクト固有 hook
ls .git/hooks/                       # サンプル一覧 (.sample 拡張子)

# 例: pre-commit でフォーマッタを実行
cat >> .git/hooks/pre-commit <<'EOF'
#!/bin/bash
set -e
terraform fmt -check -recursive
EOF
chmod +x .git/hooks/pre-commit

# プロジェクト共有用には pre-commit (Python ツール) や lefthook 等を使うのが定番
pre-commit install                   # .pre-commit-config.yaml を読み込む

よく使うレシピ

レシピ 1 — PR 前にコミットを綺麗に整える

# 5 コミットを 1 つにまとめてメッセージ書き直し
git fetch origin
git rebase -i origin/main
# エディタで 1 行目以外を fixup or squash に書き換え、保存
# その後コミットメッセージを reword で整形

# main の最新を取り込みつつ rebase
git pull --rebase origin main

# push(自分しか触らないブランチ前提で)
git push --force-with-lease origin feature

レシピ 2 — main に間違った push をしてしまった

# 自分しか push してない / 共有前のローカル開発の場合
git reset --hard HEAD~1
git push --force-with-lease origin main

# 他人も push 済みなら revert で打ち消し(履歴は残る、安全)
git revert HEAD
git push origin main

レシピ 3 — リセットしすぎて消えたブランチを復活

git reflog                                  # 「あの時の HEAD」を探す
git switch -c rescue HEAD@{12}              # 12 操作前から新ブランチ作成

レシピ 4 — 別ブランチの 1 コミットだけ取り込む

git switch main
git cherry-pick abc1234                     # OK

レシピ 5 — 巨大ファイルを誤コミット → 履歴から消す

# 直前のコミットだけ消す
git rm --cached huge.bin
echo "huge.bin" >> .gitignore
git add .gitignore
git commit --amend                          # 直前コミットを上書き

# 過去全履歴から消す(要 git-filter-repo)
git filter-repo --path huge.bin --invert-paths
git push --force-with-lease

レシピ 6 — ブランチがどこから派生したか

git merge-base main feature                 # 共通祖先のコミット SHA
git log $(git merge-base main feature)..feature --oneline   # 派生後の差分

レシピ 7 — レビューで「この変更だけ取り込んで」

# 特定コミットの内容を patch にして適用
git format-patch -1 abc1234
git am 0001-*.patch

# あるいは diff を直接適用
git show abc1234 | git apply

レシピ 8 — 各人のコミット行数 ランキング(自分の貢献量チェック)

git log --pretty=tformat: --numstat \
  | awk '{ add[$3]+=$1; del[$3]+=$2 } END { for (f in add) print add[f]+del[f], f }' \
  | sort -rn | head -n 20

コマンド早見表

# 履歴
git log --oneline --graph --all --decorate
git log -S 'function_name'
git blame -L 10,30 file

# rebase
git pull --rebase origin main
git rebase -i HEAD~5
git push --force-with-lease

# 救命系
git reflog
git reset --hard HEAD@{2}
git restore --source=HEAD~3 file

# bisect
git bisect start HEAD v1.0.0
git bisect run npm test

# worktree
git worktree add ../hotfix hotfix/login

用語集

HEAD
「現在チェックアウトしているコミット」を指すシンボリック参照。通常はブランチ名を指す。デタッチ HEAD はブランチに紐付かないコミットを直接見ている状態。
refspec / 参照
コミットを指す文字列(ブランチ名、タグ名、SHA、HEAD、HEAD~3、HEAD@{2} など)。Git の柔軟さの源泉。
HEAD~N vs HEAD^N
HEAD~N は親方向に N 個遡る(マージの場合は第 1 親優先)。HEAD^N は HEAD の N 番目の親(マージコミットの第 2 親など)。
HEAD@{N}
reflog 上で N 操作前の HEAD。HEAD@{yesterday}, HEAD@{1.hour.ago} も使える。
fast-forward
マージ対象のブランチが現ブランチの祖先に直接続いている場合、新しいマージコミットを作らず HEAD を進めるだけのマージ。--no-ff で強制的にマージコミットを作れる。
rebase vs merge
rebase は履歴を直線に整形(コミット ID は変わる)、merge は分岐の歴史を残す(マージコミットができる)。チームで使い分けポリシーを決めることが多い。
squash / fixup / reword (rebase -i)
squash = 直前コミットに統合してメッセージも結合 / fixup = 統合してメッセージは捨てる / reword = メッセージだけ書き直す。
force-with-lease
git push --force の安全版。リモートの状態が自分の知っている状態と一致する時のみ強制 push を許可。他人の push を上書きする事故を防ぐ。
cherry-pick
別ブランチの特定コミットの差分だけを現ブランチに適用して新コミットを作る操作。コミット ID は新規発行される。
revert
過去コミットを打ち消す新コミットを作る操作。履歴は残るので安全。reset は履歴を巻き戻すので破壊的。
reset --soft / --mixed / --hard
HEAD のみ動かす (soft) / HEAD + インデックス (mixed, デフォルト) / HEAD + インデックス + ワークツリー (hard) で挙動が変わる。hard のみ破壊的。
stash
ワークツリーとインデックスの変更を一時退避するスタック。pop で取り出せる。緊急の hotfix で割り込まれた時に活躍。
reflog
HEAD の移動履歴。commit/checkout/rebase/reset すべての操作が記録される。「壊した」と思った時の最強の救命綱。デフォルトで 90 日保持。
bisect
「ある時点で動いていた、今動かない」時にコミットを二分探索でバグ混入箇所を絞り込む機能。テストを git bisect run で自動化できる。
worktree
1 リポジトリで複数ディレクトリ・複数ブランチを並行 checkout する機能。stash の代替として強力。
submodule
あるリポジトリ内に別リポジトリを「特定 commit を指す」形で取り込む。複雑なので代替(パッケージ化、subtree、monorepo)も検討。
blame -w / -C
blame で「空白だけの変更を無視 (-w)」「コピー / 移動も追跡 (-C)」できる。リファクタ後の本来の作者を辿るのに便利。
filter-repo
履歴を書き換える公式推奨ツール(旧 filter-branch の後継)。誤コミットの巨大ファイル削除や機密情報除去に使う。要別途インストール。
merge-base
2 ブランチの共通祖先コミット。git merge-base main feature で取得。「派生してから何が変わったか」の起点。