Gitで過去のコミットから新しいブランチを作り作業をやり直す方法|switch -c・checkout -b・救済手順まで

Gitを使っていると「リリース直前の安定版から緊急修正だけしたい」「機能開発を途中からやり直したいが今のブランチはそのまま残したい」「他人のPRを過去のコミット時点で試したい」といった、過去の任意のコミットから新しいブランチを切って作業を再開する場面に出会います。

この記事では、git switch -cgit checkout -bを使って過去コミットから派生ブランチを作る方法を、ハッシュの調べ方・実践シナリオ・落とし穴まで体系的に解説します。resetで履歴を巻き戻すのではなく、元のブランチを無傷のまま残したうえで、新しい作業線を安全に切り出すためのガイドです。

この記事で学べること

  • 過去コミットのハッシュをgit logreflog・タグから特定する方法
  • git switch -c(推奨)とgit checkout -bの使い分け
  • 派生ブランチ作成の実践シナリオ(hotfix・やり直し・他人PRの検証・タグ起点)
  • detached HEADで作業してしまったときにブランチを後付けする救済手順
  • リモートへのpushとupstream設定、ブランチ運用の落とし穴
  • resetやrevertとの違い——いつブランチ派生が正解か
スポンサーリンク

いつ「過去コミットからブランチ」を使うべきか

Gitで履歴を扱う方法は複数あり、「過去コミットから新ブランチを作る」がベストな場面は限られます。まず判断の軸を整理しましょう。

目的 最適な手段 この記事で扱う?
過去コミットから別アプローチで作業をやり直す git switch -c <name> <SHA> ○ 本記事のメインテーマ
リリースタグから緊急修正ブランチを切る git switch -c hotfix/xxx v1.2.0 ○ シナリオで解説
履歴そのものを過去の状態に戻す(破棄) git reset --hard <SHA> × 特定コミットまで戻す方法
共有ブランチのコミットを打ち消す git revert <SHA> × コミットの取り消し方
現HEADから新ブランチを切る(通常の機能開発) git switch -c feature/xxx × 新しいブランチを作成する基本手順
誤って別ブランチに積んだコミットを移動する cherry-pick / rebase --onto × 別ブランチで作業したときの復旧
detached HEADで作業してしまった git switch -c rescueで救済 ○ このあとに解説

ポイント:過去コミットから新ブランチを作る最大のメリットは元のブランチに一切影響を与えずに試せること。resetのように既存の履歴を破壊せず、revertのように打ち消しコミットを増やしもしません。「やり直し」ではなく「別ルートを増やす」操作だと理解すると使いどころが見えてきます。

STEP 1:起点にするコミットのハッシュを特定する

派生元にしたいコミットのSHAをまず確認します。git logだけでなく、ブランチ・タグ・reflog・リモート参照も起点として指定できることを知っておくと便利です。

ハッシュ・参照を特定するコマンド
# 直近10件のコミットをSHA付きで表示
git log --oneline -10

# 分岐を見ながら履歴を追う
git log --oneline --graph --all -20

# 特定のファイル変更に関わったコミットだけ絞り込む
git log --oneline -- src/app.js

# タグから起点を選ぶ(v1.2.0 のSHAを確認)
git show-ref --tags | grep v1.2.0

# reflogで「自分の過去の操作履歴」から起点を探す
git reflog

# リモートの特定ブランチ時点を起点にする
git fetch origin
git log --oneline origin/main -5

ハッシュは先頭7〜8文字で一意なら短縮形でOKです。ブランチ名・タグ名・HEAD~3のような相対参照も使えます。

起点として指定できるもの

  • コミットSHA(例:a1b2c3d
  • タグ名(例:v1.2.0
  • ブランチ名(例:mainorigin/main
  • 相対参照(例:HEAD~5HEAD^main~3
  • reflog参照(例:HEAD@{2}

STEP 2:過去コミットから新しいブランチを作成する

Git 2.23以降はgit switch -cが推奨コマンドです。古いGitや既存の習慣でgit checkout -bを使っても機能的には同等ですが、新しく書くスクリプトや手順書ではswitch系を優先しましょう。

推奨:git switch -c でブランチ作成
# 過去コミットから新しいブランチを作り、そのまま切り替える
git switch -c feature/retry a1b2c3d

# タグから派生ブランチを作る(リリース起点のhotfix等)
git switch -c hotfix/cve-2024 v1.2.0

# HEADから3件前を起点にする
git switch -c experiment HEAD~3

# リモートの特定ブランチから派生する
git fetch origin
git switch -c review/pr-42 origin/feature/pr-42
互換:git checkout -b でも同等
# checkout -b は Git 2.23 より前からある古典的な方法
git checkout -b feature/retry a1b2c3d

# 機能的には switch -c と同じだが、checkout は多機能すぎて誤用しやすい

ポイント:-c」は「create」の意味。既にブランチが存在する場合に強制上書きしたいなら-C(大文字)を使います(慎重に)。git switchはブランチの切り替えに特化した安全な設計で、checkoutのように誤ってファイルを上書きしてしまうリスクが小さいのが利点です。

作成したブランチを確認する

ブランチ作成後の確認
# 現在のブランチが新しいブランチに切り替わっているか確認
git branch

# HEADが想定したコミットを指しているか確認
git log --oneline -3

# ブランチの起点がどこか確認
git log --oneline main..HEAD  # mainと何が違うか

STEP 3:作業してコミットし、リモートにpushする

新しいブランチに切り替わった時点で、通常の開発フローと同じように作業できます。

作業・コミット・プッシュ
# ファイルを編集
vim src/feature.js

# ステージング + コミット
git add src/feature.js
git commit -m "feat: 新アプローチで再実装"

# リモートにpush(初回は -u で upstream 設定)
git push -u origin feature/retry

-u / –set-upstream の役割

  • 初回pushに-u--set-upstream)を付けると、以降はgit pushgit pullのみでリモートと同期できる
  • 設定を確認:git branch -vvでupstream追跡状態を表示
  • 詳しくはoriginとupstreamの違いと使い分けを参照

実践シナリオ:よくある派生ブランチの作り方

シナリオ① リリースタグから hotfix ブランチを切る

本番で動いているv1.2.0に致命的なバグが見つかったが、mainブランチは次期v2.0に向けて進んでいる——そんなときはタグ起点でhotfixブランチを切り、修正後にmainにもマージします。

タグから hotfix
# タグの存在確認
git tag -l "v1.2.*"

# v1.2.0 から hotfix ブランチを作成
git switch -c hotfix/1.2.1 v1.2.0

# 修正してコミット
git add src/auth.js
git commit -m "fix: 認証ヘッダーの検証漏れを修正"

# 新しい修正タグを打ってpush
git tag -a v1.2.1 -m "hotfix for auth header"
git push origin hotfix/1.2.1 v1.2.1

修正後は通常、hotfix/1.2.1mainにもマージして同じバグが再発しないようにします。タグの詳しい運用はタグ(tag)の使い方を参照してください。

シナリオ② 機能開発を途中からやり直す

機能ブランチで作業していたが、3コミット目からの方針が間違っていた。2コミット目までは活かしたい——そんなときは2コミット目から新ブランチを切り直します。元のブランチは無傷で残るので、比較も簡単です。

機能ブランチをやり直す
# 元のブランチで作業内容を確認
git log --oneline feature/api -10

# 2コミット目のSHAを把握(例: f4e5d6a)
# そこから新ブランチを切る
git switch -c feature/api-v2 f4e5d6a

# 別アプローチで再実装して進める
# 元の feature/api は消さずに残しておけば、あとで比較できる

ポイント:「やり直し」でresetを使うと履歴が消えてしまいますが、この方法なら古いアプローチ(feature/api)と新しいアプローチ(feature/api-v2)を並べて比較できます。検証が終わって新ブランチを採用したら、古いブランチは削除しましょう。

シナリオ③ 他人のPRをローカルで試す

他メンバーのPRブランチを、そのブランチの特定時点で試したいとき。GitHubならorigin/pull/42/head参照、通常のリモートブランチならorigin/feature/xxxから派生させます。

リモートブランチから検証用ブランチ
# リモート情報を最新化
git fetch origin

# リモートブランチからローカル検証ブランチを作成
git switch -c review/pr-42 origin/feature/pr-42

# GitHubのPR番号から直接取得する場合(origin 側の fetch 設定で対応が必要)
# git fetch origin pull/42/head:review/pr-42
# git switch review/pr-42

# ビルド・テスト実行
npm install && npm test

シナリオ④ 壊れた main を過去時点から立て直す(安全策)

共有ブランチに問題のあるコミットが入ってしまい、force push以外で立て直したいとき。壊れる前のコミットから新しい保全用ブランチを切り、PRベースで段階的に戻します。

問題発生前の状態から保全ブランチ
# 問題発生前のSHA(例:9876543)から保全用ブランチを作成
git switch -c recovery/main-safe 9876543

# 必要なファイルや差分をこのブランチ上で整理
# PRを作成してレビュー後に main にマージ
git push -u origin recovery/main-safe

注意:共有ブランチ(main/develop)に対してgit reset --hard + git push --forceを使うのは原則避けます。他メンバーのローカル環境が壊れる可能性があるためです。派生ブランチ経由でPRに持っていくのが事故の起きにくい運用です。

detached HEADで作業してしまったときの救済

「過去コミットにcheckoutしてそのまま編集・コミットしてしまった」——これはdetached HEAD状態での作業で、何もしないと次に別ブランチへ切り替えた瞬間そのコミットはどこからも参照されなくなり、いずれGCで消えます。

detached HEAD 状態を確認
# HEADが detached か確認
git status
# → "HEAD detached at a1b2c3d" と表示される場合は要注意

# この状態でコミットしたSHAをメモしておく
git log --oneline -3

失う前に、その場でブランチを作ってコミットを救済します。以下のコマンド1発で、今いる位置(detached HEAD)をブランチ化できます。

detached HEAD をブランチ化して救済
# 今いる位置をそのまま新しいブランチにする
git switch -c rescue/my-work

# これで rescue/my-work に今のコミット含めて紐づいた
git log --oneline -5

# 必要ならリモートへpushして保全
git push -u origin rescue/my-work

ポイント:detached HEADで作ったコミットは、他のブランチに切り替える前ならgit switch -cでブランチ化すれば失われません。既に切り替えてしまった場合も、直近ならgit reflogでSHAを探してgit switch -c rescue <SHA>で復活できます。

detached HEAD自体の解説はdetached HEAD状態から元の作業ブランチに戻す方法に詳しい手順があります。

git switch と git checkout の使い分け

歴史的にcheckoutが一手で「ブランチ切替+ファイル復元+新規ブランチ作成」をこなしていましたが、機能が多すぎて誤用が起きやすいため、Git 2.23でswitchrestoreに役割が分割されました。

やりたいこと 新コマンド(推奨) 旧コマンド
既存ブランチに切り替え git switch main git checkout main
HEADから新ブランチ作成+切替 git switch -c new git checkout -b new
過去SHAから新ブランチ作成 git switch -c new <SHA> git checkout -b new <SHA>
ファイルを特定コミットの状態に戻す git restore --source <SHA> file git checkout <SHA> -- file
detached HEADで過去コミットを見る git switch --detach <SHA> git checkout <SHA>

どちらを使うべきか

  • Git 2.23以降ならswitch/restoreが推奨
  • 新メンバー・新規スクリプトにはswitch系で教える(誤操作が減る)
  • 古い教材や既存スクリプトはcheckoutのままでも動作に問題はない
  • CI/CDでgit switchが使えないほど古いGitは最新化を検討

やってはいけない落とし穴

detached HEADを知らずに作業して離脱する

過去コミットにcheckoutして編集・コミットしたまま他ブランチへ切り替えると、そのコミットはどこのブランチにも属さずreflog期限(既定90日)で消滅します。コミットが残っていても、見つける手段がreflogしかなくなります。過去コミットを起点に作業するなら、最初からgit switch -c <name> <SHA>でブランチを作ってから始めましょう。

ブランチ名の命名衝突

既に同じ名前のブランチがあるとgit switch -cは失敗します。気付かずに強制作成(-C)を使うと元のブランチを上書きしてしまう事故が起きます。命名前にgit branch | grep <name>git branch -aで確認する習慣を付けましょう。チーム内ではfeature/hotfix/experiment/のような接頭辞でスコープを明確にすると衝突が減ります。

過去コミットから切ったブランチをmainに force push で戻す

「過去のきれいな状態に戻したい」からといって、派生ブランチをmaingit push --forceで上書きすると、他メンバーのローカルが破壊されます。安全な戻し方は、派生ブランチからPRを作って通常のマージフローで戻すことです。どうしても履歴を一本化したい場合でも--force-with-lease+事前合意を徹底します。

古いSHAを指定してチェックアウトしたら依存ファイルが壊れる

過去コミット時点ではNode.jsやライブラリのバージョンが今と違う場合があります。古いコミットに移動したらpackage-lock.jsonGemfile.lockの整合性が崩れ、ビルドが通らないことがあります。依存ファイルも時点コピーであることを意識し、必要ならnpm cibundle installを再実行してから作業開始しましょう。

起点コミットをreflog頼みで探す

reflogは便利ですがローカル限定かつ期限付きです。チームで共有したい「振り返るべき重要な時点」はタグを打っておくのが本道です。「過去の安定版から派生」を頻繁に行うプロジェクトは、リリース時にタグ運用を標準化しましょう。

よくある質問

Qgit switch -c と git checkout -b、どちらを使えばいい?
AGit 2.23以降のバージョンならgit switch -cを推奨します。機能は同じですがswitchはブランチ操作専用に設計されていて誤操作が起きにくいためです。既存の手順書やCIにcheckout -bが残っていても動作は同じなので慌てて置き換える必要はありません。
Qブランチを作る前に誤って過去コミットに checkout してしまった
Aそのままgit switch -c rescue/my-branchを実行すれば、現在位置をブランチ化できます。まだ別ブランチに切り替えていなければ作業内容は失われません。
Q派生ブランチから元の main にマージしたい場合はどうする?
A通常のPRフローと同じです。mainに切り替えてからgit merge feature/retry、またはGitHub/GitLabのプルリクエストでマージします。mergeとrebaseの違いはrebaseとmergeの違いと使い分けを参照してください。
Qgit switch -c でエラー「already exists」が出る
A同名のブランチが既に存在しています。git branch -aで確認して別名にするか、不要ならgit branch -D <name>で削除してから作り直してください。削除はブランチを削除する方法に詳しい手順があります。
Q作ったブランチがリモートにpushされない
A初回pushにはgit push -u origin <branch-name>が必要です。以降はgit pushだけでリモートに反映されます。upstream設定はgit branch -vvで確認できます。
Q過去のファイル状態だけ取りたい(ブランチは作りたくない)
Agit restore --source=<SHA> -- <path>で特定ファイルだけを過去時点に戻せます。詳しくは特定のファイルだけ前のコミットに戻す方法を参照してください。
Qmainにresetしてしまって過去コミットが見えなくなった
Agit reflogで過去のHEAD移動履歴からSHAを探し、git switch -c recovery <SHA>で救済ブランチを作ります。既にgit push --forceしてしまった場合はリモート側の復旧は難しいので、CI履歴やチームメンバーのローカルから該当SHAを共有してもらって取り戻します。

関連記事

まとめ

  • 過去コミットから派生ブランチを切るメイン用途は「やり直し」「hotfix」「検証」「救済」の4つ
  • 起点はSHA・タグ・リモートブランチ・相対参照いずれも指定可
  • Git 2.23以降はgit switch -c <name> <ref>が推奨(checkout -bも同等)
  • 初回pushには-u origin <name>でupstream設定を忘れず
  • detached HEADで作業してしまってもgit switch -cで救済できる
  • 共有ブランチへのforce pushは避け、派生ブランチ→PRの王道フローで戻す

resetやrevertが「履歴を書き換える/打ち消す」操作なのに対し、過去コミットから派生ブランチを作るのは「もう1本の作業線を増やす」非破壊的な操作です。元のブランチを壊さずに安全に実験・復旧ができるため、チーム開発でもっともトラブルが起きにくい選択肢として使いこなしましょう。