◀ 21.

Gitでローカルを戻す前に|reset・restoreの違いと退避範囲

▶

Gitで戻す前に、branchの履歴・index・作業ツリーを区別します。必要な作業を保存し、全体の置換と1ファイルの復元を別に判断します。

Gitで戻す前に、branchの履歴・index・作業ツリーを区別します。必要な作業を保存し、全体の置換と1ファイルの復元を別に判断します。

この記事の要点
  • 戻す対象がbranch全体か1ファイルかを先に決める。reset --hardは確認用コマンドではない
  • reset --hardは現在のbranch・index・作業ツリーを変更する。退避branchだけでは未コミットの作業は保存されない
  • 未追跡/ignoreでも書込みの邪魔になるパスはreset --hardで失い得る。cleanによる削除は別判断
  • 1 ファイルだけ戻すなら git restore --source=origin/main -- ファイル
  • reflogはローカル参照の移動記録。未保存作業や全commitの復元を保証するバックアップではない

全体を置き換える操作の前提

次は追跡先のcommitへ現在branchを移す旧例です。通常のpull失敗への対処として実行しません。未コミット作業・未共有commit、現在branch/detached HEAD、remote URLと対象ref、進行中の処理を確認し、必要な作業を別途保存してから判断します。

この旧例の前提と注意:全remote取得もresetも確認用ではありません。現在branchと対象commitを確認し、未保存作業の退避を検証します。masterは固定の正解ではありません。

git fetch --all
git reset --hard origin/master

main/masterは例示名で、サービス名から対象を決めません。実在するrefと取得設定を確認します。次のmain版も別の旧例で、master版に続けて実行する手順ではありません。

この旧例の前提と注意:mainを現在branchへ置き換える旧例です。未追跡/ignoreを含め必要な内容を失わないか確認し、他の旧例と一括実行しません。

git fetch origin
git reset --hard origin/main

自分のブランチ名とリモート追跡ブランチの名前は git branch -a で確認できます。

各コマンドが何をしているか

  1. git fetch: リモートからオブジェクト等を取得し、refspecに対応する追跡参照やFETCH_HEAD等を更新します。通常のfetchだけでは作業ツリーを統合しません。origin/mainが必ず更新されるとは限らず、--allもskipFetchAll等の設定を確認します
  2. git reset --hard origin/main: 今いるブランチの指す先を origin/main と同じコミットに付け替え、インデックス(ステージ)と作業ツリーもそのコミットの内容で上書きします

git pull はfetch後に指定/設定された方式で現在branchへ取り込みます。merge/rebase/ff-only等を区別し、分岐による拒否をresetで回避しません。それに対して reset --hard は、ローカル側を捨てて置き換える操作です。目的に応じて使い分けてください。

実行前に:消えるもの・消えないもの

対象reset --hard 後
追跡中ファイルの未コミットの変更消える(reflog にも残らない)
ステージ済み(add 済み)の変更消える
未 push のローカルコミット現在branchの到達対象から外れる場合がある。他refやreflog/オブジェクトの保持状態に依存し復元保証なし
Git 管理外の新規ファイル(untracked)通常は対象外でも、書込みの邪魔になるパスは削除/上書きされ得る
.gitignore 対象のファイル(.env など)保護保証なし。対象commitがそのパスを追跡する場合等は注意
他のローカルブランチ通常そのrefは動かないが、作業ツリー全体の保存保証とは別

未コミット作業はreflogで内容を復元できるものではありません。add済みのオブジェクト等から回収できる可能性に頼らず、必要な内容を外部コピーや確認済みの退避で保存します。

この旧例の前提と注意:退避branchはcommitへの参照で、作業/index/未追跡ファイルを保存しません。既存の退避名を上書きしません。stash -uは未追跡を含みますがignoredは含まず、全submoduleや外部ファイルの完全バックアップでもありません。保存対象と復元結果を確認します。

# 今の状態をブランチとして残しておく(コミット済みの内容の保険)
git branch backup-before-reset

# 未コミットの変更を一時退避する(untracked も含める場合は -u)
git stash push -u -m "before reset"

未追跡ファイルの削除範囲を確認する

git cleanは未追跡ファイル等の削除であり、同期に必須ではありません。まず-nと対象pathspecで予定を確認し、必要な未追跡作業を保存します。dry-runと実行の間に新しいファイルが増える場合もあり、予定表示だけで削除の安全は保証されません。

この旧例の前提と注意:2行目は実削除なので、一緒にコピー実行しません。-xはignoredも、-Xはignoredだけを対象にします。入れ子repo等には別の制約があり、強制回数を増やして回避しません。今回はdry-runだけを検証し、実cleanは行いません。

git clean -n -d     # 削除されるファイル・ディレクトリを表示するだけ
git clean -f -d     # 実際に削除

-x を付けると .gitignore で無視しているファイル(.env や node_modules、vendor など)まで消えます。設定ファイルを失うことがあるため、意図がない限り付けないでください。

特定のファイルだけリモートの状態に戻す

ブランチ全体ではなく、一部のファイルだけリモートと同じにしたい場合は次のようにします(git restore は Git 2.23 以降)。

この旧例の前提と注意:restoreは既定で作業ツリーだけ、次のcheckoutは指定元の内容をindexにも反映するため完全同義ではありません。元作業を退避し、復元元に存在しない追跡pathの削除やpathspec範囲にも注意します。2つは代替例で一括実行しません。

git fetch origin
git restore --source=origin/main -- path/to/file.php

# 古い Git の場合
git checkout origin/main -- path/to/file.php

確認方法

git status
# On branch main
# Your branch is up to date with 'origin/main'.
# nothing to commit, working tree clean

git log --oneline -1          # HEAD のコミット
git log --oneline -1 origin/main

同じOIDは比較したcommitが同じことを示すだけです。追跡参照は取得時点の情報で、サーバーがその後も同じとは限りません。clean表示でもignoredファイルやsubmodule等を含む実ディレクトリ全体の一致は保証されず、未追跡ファイルがあるだけで削除しません。

間違えて reset したときの戻し方

reflogに旧OIDが残りオブジェクトが存在すれば、旧commitを特定して新しい退避ref等で保持できる場合があります。reflogはローカルの設定/有効期限やprune等に依存し、未コミット内容のバックアップではありません。

この旧例の前提と注意:HEAD@{1}は固定の復旧先ではありません。既存の作業を確認・保存し、reflogの実OIDと内容を調べてから復旧方法を判断します。次のhard resetを自動的な戻し方として実行しません。

git reflog
# a1b2c3d HEAD@{0}: reset: moving to origin/main
# 9f8e7d6 HEAD@{1}: commit: 作業中の修正

git reset --hard HEAD@{1}     # reset 直前の状態に戻す
# または退避ブランチから
git reset --hard backup-before-reset

ORIG_HEADはreset等で更新されるため、常に望む過去を指すわけではありません。値と履歴を確認し、現在の作業を退避する前に再びhard resetを行わないでください。

よくある質問

push 済みのコミットを取り消したい場合も同じ手順?

いいえ。この記事の手順は「ローカルをリモートに合わせる」ものです。共有済みの変更はgit revertで打ち消しcommitを追加する方法を検討しますが、競合・依存・テストとreviewは必要です。共有ブランチで reset して force push すると、他の人の履歴と食い違います。

サブモジュールがある場合は?

submoduleは別repoです。親のresetだけで各作業ツリーが一致するとは限りません。各submoduleの未保存/未共有作業・URL/信頼・更新方式を先に確認します。update --init --recursiveは取得/checkout等を伴い、既定checkoutではdetached HEADになり得るので、一律の後処理にしません。

関連

作業ツリーとindexの違いを新規repoで確認する

次はBash/Git 2.28以降、空フォルダ用です。既存のrestore-practiceがあれば停止します。生成した練習ファイルだけを変更し、reset/cleanやネットワーク通信は行いません。global設定も変えません。

set -eu
if [ -e restore-practice ] || [ -L restore-practice ]; then
    printf 'Already exists: restore-practice\n' >&2; exit 1
fi
git init -b main restore-practice
git -C restore-practice config user.name Training
git -C restore-practice config user.email training@example.invalid
printf 'base\n' > restore-practice/sample.txt
git -C restore-practice add sample.txt
git -C restore-practice commit -m Base
printf 'staged\n' > restore-practice/sample.txt
git -C restore-practice add sample.txt
printf 'working\n' > restore-practice/sample.txt
git -C restore-practice restore --source=HEAD -- sample.txt
printf 'worktree: '; cat restore-practice/sample.txt
printf 'index: '; git -C restore-practice show :sample.txt
git -C restore-practice restore --source=HEAD --staged --worktree -- sample.txt
git -C restore-practice diff --exit-code
git -C restore-practice diff --cached --exit-code

最初のrestore後はworktreeがbase、indexがstagedです。両方を指定したrestore後は差分がなくなります。通常の作業repoに置き換えて実行する前には、失ってよい内容か確認してください。

退避から復元するときの確認順

  1. 残したい作業ファイル/未追跡/ignored/submoduleを別々に確認する。
  2. 退避branchのOIDやstashの内容を読み、必要なものが保存されているか確認する。
  3. 復旧候補のcommitを特定し、現在の作業を上書きしない形で内容を確認する。
  4. stashのapplyも競合し得る。復元後に差分と動作を確認してから、退避を保持/整理するか判断する。

取込みはpull、履歴編集はrebase、送信条件はpushへ。Git親ページの子ページから選択してください。

公式資料と検証範囲

2026年10月にreset・revert・initのshared・clean・restore・checkout・stash・reflog・submoduleを確認しました。旧コードを保持し誤案内は近接訂正しています。新規ローカルrepoで追加例とrestore/revert・設定/範囲を検査しましたが、hard reset・実clean・強制更新/サーバー直接変更、実サービスの権限/保護/CIや全submodule構成を検証したものではありません。

子ページ

子ページはありません

同階層のページ
  1. 用語一覧
  2. エラー一覧
  3. git本体のインストール(Linux)
  4. Linuxサーバーへのgit導入とクライアントのセットアップ
  5. リモートリポジトリをローカルリポジトリとしてクローンする方法
  6. リモートとローカルのリポジトリを同期(pull)する方法
  7. 設定の確認
  8. gitユーザー名とemailの設定
  9. リモートリポジトリの作成
  10. ローカルリポジトリの作成
  11. 新規ファイル/ディレクトリをインデックスに登録
  12. インデックスの登録状態を確認
  13. ローカルリポジトリの変更をコミット
  14. コミット履歴の確認
  15. クライアントからリモートリポジトリの接続設定、確認、削除
  16. リポジトリへのプッシュ
  17. リモートリポジトリからクライアントへのSSHクローン
  18. リモートとローカルの差分表示
  19. バージョンの確認
  20. プロキシの設定
  21. ローカルをリモートリポジトリの状態に戻す
  22. ブランチの作成, 一覧表示, 切り替え
  23. ブランチのマージと削除
  24. リベース
  25. .gitignoreの書き方
  26. .gitignoreの設定が反映されない場合
  27. 特定のファイルをgitの管理から外す方法
  28. 参照(ORIG_HEAD, HEAD, FETCH_HEAD)
  29. git rm [-r --cached] の取り消し
  30. 一部のディレクトリ/ファイルのみをリポジトリから復元する方法
  31. ローカルとリモートリポジトリの有無を同期
  32. pushの取消し方法
  33. マージツールの起動方法
  34. Gitで「MERGING」の状態

最近更新/作成されたページ