よく使うGitコマンドと、それが何をしているか
Gitのコマンドは、覚えるより「いま何がどこにあるか」を掴むほうが早いです。
この記事では、実際に毎日使っているコマンドを、何をしているかの説明つきで並べます。順番は使う頻度ではなく、理解の順番にしました。
Gitが管理している3つの場所という考え方と、それに沿ったコマンドの整理。特に「戻す」系は似たコマンドが多く、取り違えると作業が消えます。実際に消した経験も含めて書きます。
まず、3つの場所を知る
Gitのコマンドが分かりにくいのは、ファイルが3つの場所に同時に存在するからです。ここを掴むと、大半のコマンドは「どこからどこへ動かすか」で説明がつきます。
| 場所 | 何があるか | 失うとどうなるか |
|---|---|---|
| 作業ツリー | いまエディタで見ているファイル | 戻せない |
| ステージ | 次のコミットに含めると決めたもの | 作業ツリーから入れ直せる |
| 履歴 | コミット済みのもの | だいたい取り戻せる |
右の列が重要です。コミットしていないものだけが、本当に消えます。逆に言えば、コミットさえしてあれば、たいていの失敗は取り返せます。
作業ツリー --git add--> ステージ --git commit--> 履歴
(編集中) (準備中) (記録済み)
状態を見る
作業の8割はこれです。何かする前に、いまどうなっているかを見ます。
M frontend/src/app/page.tsx ← 変更あり(未ステージ)
M frontend/src/lib/data.ts ← 変更あり(ステージ済み)
?? frontend/src/lib/new-file.ts ← 新規(Gitがまだ知らない)
左の2文字が、ステージと作業ツリーの状態を表します。--short を付けると1ファイル1行になり、ファイル数を数えられます。これが後で効きます。
c5ce23e Merge pull request #11 from kisaku39/feat/next-16
29aa412 chore(deps): Next.js 16 / React 19 へ移行
ba625e3 Merge pull request #10 from ...
直近5件の履歴。--oneline が無いと1コミットが5行になり、画面が埋まります。
git diff # 作業ツリーの変更(未ステージ)
git diff --staged # ステージ済みの変更
git diff --stat # ファイル名と増減行数だけ
--stat は、変更が意図した範囲に収まっているかを一目で見るときに使います。
記録する
git add ファイル名 # 指定したものをステージへ
git add -A # 変更・新規・削除をすべてステージへ
git commit -m "説明" # ステージの中身を履歴へ記録
git add -A は便利ですが、意図しないファイルまで巻き込みます。実行前に git status --short で並んでいるものを確認する習慣にしておくと安全です。
私は一度、5ファイル直したはずのコミットに2ファイルしか入っていない状態でpushしました。ビルドも通り、デプロイも成功し、何も直っていませんでした。git status --short の行数を数えるだけで、pushする前に気づけた失敗です。
git commit --amend -m "新しい説明"
直前のコミットを作り直します。メッセージの誤字直しや、入れ忘れたファイルの追加に使います。push済みのコミットには使わないでください。履歴が別物になり、他の人の手元と食い違います。
戻す ── ここが一番危ない
似た名前のコマンドが複数あり、取り違えると作業が消えます。用途で分けて覚えるのが安全です。
| やりたいこと | コマンド | 危険度 |
|---|---|---|
| ステージから降ろす(編集は残す) | git restore --staged ファイル |
安全 |
| ファイルの編集を捨てる | git restore ファイル |
戻せない |
| コミットを打ち消す新しいコミットを作る | git revert コミットID |
安全 |
| 履歴を巻き戻す(編集は残す) | git reset --soft コミットID |
注意 |
| 履歴を巻き戻して全部捨てる | git reset --hard |
非常に危険 |
reset は「取り消し」ではなく「破棄」
git reset --hard は、直前の操作を取り消したいときに手が伸びやすいコマンドです。しかし実際にやることは違います。
コミット済みの変更 → 履歴に残っているので取り戻せる
未コミットの編集 → 消える。取り戻す手段は無い
履歴に無いものは、履歴から復元できません。当たり前ですが、この当たり前が事故の形になります。私はこれで、書き換えたばかりの5ファイルを失いました。
「一旦きれいにしたい」「ブランチを切り替えたい」という理由でresetを使いたくなったら、その用途は git stash のほうです。捨てずに退避してくれます。
revert と reset の違い
どちらも「戻す」ですが、履歴の扱いが逆です。
reset … 履歴そのものを巻き戻す(無かったことにする)
revert … 「打ち消す」コミットを新しく積む(戻した記録が残る)
すでにpushしたものを戻すときは、必ずrevertです。resetで消すと、他の人の手元にある履歴と食い違い、収拾がつかなくなります。
退避する
git stash # 変更を退避して、作業ツリーをきれいにする
git stash -u # 未追跡(新規)ファイルも一緒に退避
git stash list # 退避したものの一覧
git stash pop # 最後に退避したものを戻す
git stash drop # 退避したものを捨てる
-u を付ける場面が意外と多いです。既定のstashは、Gitがまだ知らない新規ファイルを退避しません。そのままpullすると「未追跡のファイルを上書きすることになるので中断する」と止められます。
git stash push -m "pull前の退避" のようにメモを残せます。stashは溜まると何が何だか分からなくなるので、いつ・なぜ退避したかを書いておくと後で助かります。
ブランチを扱う
git branch # ブランチ一覧(* が現在地)
git branch --show-current # 現在のブランチ名だけ
git checkout -b feat/xxx # 新しいブランチを作って移動
git checkout main # 既存のブランチへ移動
git branch -d feat/xxx # ブランチを削除
git branch -d はマージ済みのブランチしか消しません。未マージの変更が残っていれば拒否してくれます。大文字の -D は確認なしで消すので、日常では使わないほうが安全です。
本番に直接入れると、壊れていた場合に「戻す」しか選択肢がありません。ブランチで作業すれば、本番を触らないまま動作確認できます。デプロイ先によっては、ブランチごとに確認用のURLを作ってくれます。確認の機会を1回増やすだけで、事故の大きさが変わります。
共有する
git fetch # リモートの状態を取ってくる(作業ツリーは変えない)
git pull # fetch + 自分のブランチに取り込む
git push # 自分のコミットをリモートへ送る
git push が拒否されることがあります。
! [rejected] main -> main (non-fast-forward)
hint: Updates were rejected because the tip of your current
hint: branch is behind its remote counterpart.
これは正しい動作です。手元がリモートより遅れている状態でpushすると、リモート側の新しいコミットが消えます。Gitはそれを防いでいます。
対処は「先に取り込む」です。git pull してから、あらためてpushします。ここで --force を使うと、止めてくれた意味が無くなります。
困ったときの2つ
操作の履歴をたどる ── reflog
c5ce23e HEAD@{0}: commit: ...
682faf3 HEAD@{1}: reset: moving to HEAD ← ここで何かした
682faf3 HEAD@{2}: pull: Fast-forward
git log がコミットの履歴なのに対し、reflog は「自分がGitに何をしたか」の履歴です。checkout、reset、pull、commit——すべて記録されています。
「変更が消えた」「いつのまにか違うブランチにいる」というときは、まずこれを見ます。何が起きたかを推測せずに済みます。私も、消えた原因がresetだったことをこれで特定しました。
「別のプロセスが動作中」と言われる ── index.lock
fatal: Unable to create '.git/index.lock': File exists.
Another git process seems to be running in this repository.
Gitは操作のたびに .git/index.lock という目印のファイルを作り、終わったら消します。何らかの理由で消し損ねると、このファイルが残り続けます。
そしてロックが残っている間、Gitはすべての操作を拒否します。本当に別のプロセスが動いている可能性があるからです。
# 本当に他でGitを動かしていないことを確認してから
rm -f .git/index.lock
このファイルは0バイトで、中身がありません。Gitのデータは一切入っていない、単なる目印です。他でGitを動かしていないことさえ確かなら、消して問題ありません。
私がこれを踏んだのは、同じリポジトリに2つの経路から触っていたためでした。片方に書き込み権限が足りず、ロックを作れたのに消せませんでした。.git は排他制御を前提に作られているので、複数の経路から同時に触る構成は避けるべきです。
1日の流れに並べると
git status --short # 汚れていないか確認
git pull # 最新を取り込む
git checkout -b feat/xxx # 作業用のブランチへ
(編集する)
git status --short # ファイル数を数える
git diff # 中身を確認
git add -A
git commit -m "..."
git push -u origin feat/xxx # ブランチのままpush
(確認用URLで動作確認)
(問題なければマージ)
git checkout main
git pull
git branch -d feat/xxx # 役目を終えたブランチを削除
この中でいちばん省かれやすいのが、最初と真ん中の git status --short です。そして今日書いた失敗は、どちらもここを飛ばしたことが原因でした。
まとめ
まず、コミットしていないものだけが本当に消えること。逆に言えば、こまめにコミットしておけば、たいていの失敗は取り返せます。危ない作業の前にコミットを1つ挟むのは、いちばん安いお守りです。
次に、reset は取り消しではなく破棄だということ。状態を整えたいだけなら stash を使います。用途で選び分けるだけで、事故の大半は避けられます。
そして、何かする前に状態を見ること。git status --short と git diff --stat の2つを挟むだけで、「意図しないものが混ざっている」「意図したものが入っていない」の両方に気づけます。
最後に、止められたときは理由があること。pushの拒否も、ロックによる中断も、Gitが壊れないように守っている動作です。--force や強制削除で押し通す前に、なぜ止まったのかを読むほうが、結果的に速いです。
関連記事

通ったビルドが、何も直していなかった
codegenもビルドもコミットもpushもデプロイも、すべて成功した。それでも直したかったものは1つも直っていなかった。変更が丸ごと消えたことで辻褄が合ってしまい、検査をすり抜けた話と、それを見つけるための確認について。
自分のブログに記事が投稿できない — WAFの誤検知と、渡し方を変える解決
自分のブログに、自分で書いた記事が投稿できなくなりました。 原因はサーバーのWAF(Webアプリケーションファイアウォール)でした。記事の本文に含まれるコードが、攻撃と誤検知されて遮断されていたのです。回避を4種類試して […]
本番公開でつまずいた11のこと — 仕組みから解説
前回、ローカルで作ったサイトを本番公開するまでの記録を書きました。今回はその中で出てきた仕組みを、初めて触る人向けに整理して解説します。 作業記録だけだと「こう直した」で終わってしまい、次に似た場面で応用が効きません。な […]