Gitを使っていると「リリース直前の安定版から緊急修正だけしたい」「機能開発を途中からやり直したいが今のブランチはそのまま残したい」「他人のPRを過去のコミット時点で試したい」といった、過去の任意のコミットから新しいブランチを切って作業を再開する場面に出会います。
この記事では、git switch -cとgit checkout -bを使って過去コミットから派生ブランチを作る方法を、ハッシュの調べ方・実践シナリオ・落とし穴まで体系的に解説します。resetで履歴を巻き戻すのではなく、元のブランチを無傷のまま残したうえで、新しい作業線を安全に切り出すためのガイドです。
この記事で学べること
- 過去コミットのハッシュを
git log・reflog・タグから特定する方法 git switch -c(推奨)とgit checkout -bの使い分け- 派生ブランチ作成の実践シナリオ(hotfix・やり直し・他人PRの検証・タグ起点)
- detached HEADで作業してしまったときにブランチを後付けする救済手順
- リモートへのpushとupstream設定、ブランチ運用の落とし穴
- resetやrevertとの違い——いつブランチ派生が正解か
いつ「過去コミットからブランチ」を使うべきか
Gitで履歴を扱う方法は複数あり、「過去コミットから新ブランチを作る」がベストな場面は限られます。まず判断の軸を整理しましょう。
ポイント:過去コミットから新ブランチを作る最大のメリットは元のブランチに一切影響を与えずに試せること。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) - ブランチ名(例:
main、origin/main) - 相対参照(例:
HEAD~5、HEAD^、main~3) - reflog参照(例:
HEAD@{2})
STEP 2:過去コミットから新しいブランチを作成する
Git 2.23以降はgit switch -cが推奨コマンドです。古いGitや既存の習慣でgit checkout -bを使っても機能的には同等ですが、新しく書くスクリプトや手順書ではswitch系を優先しましょう。
# 過去コミットから新しいブランチを作り、そのまま切り替える 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
# 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 push・git pullのみでリモートと同期できる - 設定を確認:
git branch -vvでupstream追跡状態を表示 - 詳しくはoriginとupstreamの違いと使い分けを参照
実践シナリオ:よくある派生ブランチの作り方
シナリオ① リリースタグから hotfix ブランチを切る
本番で動いているv1.2.0に致命的なバグが見つかったが、mainブランチは次期v2.0に向けて進んでいる——そんなときはタグ起点でhotfixブランチを切り、修正後にmainにもマージします。
# タグの存在確認 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.1をmainにもマージして同じバグが再発しないようにします。タグの詳しい運用はタグ(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で消えます。
# HEADが detached か確認 git status # → "HEAD detached at a1b2c3d" と表示される場合は要注意 # この状態でコミットしたSHAをメモしておく git log --oneline -3
失う前に、その場でブランチを作ってコミットを救済します。以下のコマンド1発で、今いる位置(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でswitchとrestoreに役割が分割されました。
どちらを使うべきか
- 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 で戻す
「過去のきれいな状態に戻したい」からといって、派生ブランチをmainにgit push --forceで上書きすると、他メンバーのローカルが破壊されます。安全な戻し方は、派生ブランチからPRを作って通常のマージフローで戻すことです。どうしても履歴を一本化したい場合でも--force-with-lease+事前合意を徹底します。
古いSHAを指定してチェックアウトしたら依存ファイルが壊れる
過去コミット時点ではNode.jsやライブラリのバージョンが今と違う場合があります。古いコミットに移動したらpackage-lock.jsonやGemfile.lockの整合性が崩れ、ビルドが通らないことがあります。依存ファイルも時点コピーであることを意識し、必要ならnpm ciやbundle installを再実行してから作業開始しましょう。
起点コミットをreflog頼みで探す
reflogは便利ですがローカル限定かつ期限付きです。チームで共有したい「振り返るべき重要な時点」はタグを打っておくのが本道です。「過去の安定版から派生」を頻繁に行うプロジェクトは、リリース時にタグ運用を標準化しましょう。
よくある質問
git switch -cを推奨します。機能は同じですがswitchはブランチ操作専用に設計されていて誤操作が起きにくいためです。既存の手順書やCIにcheckout -bが残っていても動作は同じなので慌てて置き換える必要はありません。git switch -c rescue/my-branchを実行すれば、現在位置をブランチ化できます。まだ別ブランチに切り替えていなければ作業内容は失われません。mainに切り替えてからgit merge feature/retry、またはGitHub/GitLabのプルリクエストでマージします。mergeとrebaseの違いはrebaseとmergeの違いと使い分けを参照してください。git branch -aで確認して別名にするか、不要ならgit branch -D <name>で削除してから作り直してください。削除はブランチを削除する方法に詳しい手順があります。git push -u origin <branch-name>が必要です。以降はgit pushだけでリモートに反映されます。upstream設定はgit branch -vvで確認できます。git reflogで過去のHEAD移動履歴からSHAを探し、git switch -c recovery <SHA>で救済ブランチを作ります。既にgit push --forceしてしまった場合はリモート側の復旧は難しいので、CI履歴やチームメンバーのローカルから該当SHAを共有してもらって取り戻します。関連記事
- 【Git】新しいブランチを作成する基本的な手順 — 現HEADから普通にブランチを切る基礎
- 【Git】detached HEAD状態から元の作業ブランチに戻す方法 — 切り離し状態からの復帰手順
- 【Git】間違えて別ブランチで作業したときの復旧方法 — cherry-pick/rebaseでの移動
- 【Git】コミットの取り消し方 — reset/revert/amendの使い分け
- 【Git】特定のコミットまで戻す方法 — 履歴を戻す別アプローチ
- 【Git】タグ(tag)の使い方 — リリース起点のブランチ派生に必須
- 【Git】rebaseとmergeの違いと使い分け — 派生ブランチを戻すときの選択肢
- 【Git】originとupstreamの違いと使い分け — リモート追跡の仕組み
- 【Git】ブランチを削除する方法 — 不要になった派生ブランチの整理
まとめ
- 過去コミットから派生ブランチを切るメイン用途は「やり直し」「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本の作業線を増やす」非破壊的な操作です。元のブランチを壊さずに安全に実験・復旧ができるため、チーム開発でもっともトラブルが起きにくい選択肢として使いこなしましょう。