KiSAKU
技術系9分で読めます

よく使うGitコマンドと、それが何をしているか

公開

Gitのコマンドは、覚えるより「いま何がどこにあるか」を掴むほうが早いです。

この記事では、実際に毎日使っているコマンドを、何をしているかの説明つきで並べます。順番は使う頻度ではなく、理解の順番にしました。

この記事で扱うこと

Gitが管理している3つの場所という考え方と、それに沿ったコマンドの整理。特に「戻す」系は似たコマンドが多く、取り違えると作業が消えます。実際に消した経験も含めて書きます。

まず、3つの場所を知る

Gitのコマンドが分かりにくいのは、ファイルが3つの場所に同時に存在するからです。ここを掴むと、大半のコマンドは「どこからどこへ動かすか」で説明がつきます。

場所 何があるか 失うとどうなるか
作業ツリー いまエディタで見ているファイル 戻せない
ステージ 次のコミットに含めると決めたもの 作業ツリーから入れ直せる
履歴 コミット済みのもの だいたい取り戻せる

右の列が重要です。コミットしていないものだけが、本当に消えます。逆に言えば、コミットさえしてあれば、たいていの失敗は取り返せます。

流れ
作業ツリー  --git add-->  ステージ  --git commit-->  履歴
   (編集中)              (準備中)           (記録済み)

状態を見る

作業の8割はこれです。何かする前に、いまどうなっているかを見ます。

git status –short
 M frontend/src/app/page.tsx      ← 変更あり(未ステージ)
M  frontend/src/lib/data.ts       ← 変更あり(ステージ済み)
?? frontend/src/lib/new-file.ts   ← 新規(Gitがまだ知らない)

左の2文字が、ステージと作業ツリーの状態を表します。--short を付けると1ファイル1行になり、ファイル数を数えられます。これが後で効きます。

git log –oneline -5
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 は、変更が意図した範囲に収まっているかを一目で見るときに使います。

記録する

基本の3つ
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 は、直前の操作を取り消したいときに手が伸びやすいコマンドです。しかし実際にやることは違います。

git reset –hard が消すもの
コミット済みの変更   → 履歴に残っているので取り戻せる
未コミットの編集     → 消える。取り戻す手段は無い

履歴に無いものは、履歴から復元できません。当たり前ですが、この当たり前が事故の形になります。私はこれで、書き換えたばかりの5ファイルを失いました。

状態を整えたいだけなら stash

「一旦きれいにしたい」「ブランチを切り替えたい」という理由でresetを使いたくなったら、その用途は git stash のほうです。捨てずに退避してくれます。

revert と reset の違い

どちらも「戻す」ですが、履歴の扱いが逆です。

同じ「戻す」でも
reset  … 履歴そのものを巻き戻す(無かったことにする)
revert … 「打ち消す」コミットを新しく積む(戻した記録が残る)

すでにpushしたものを戻すときは、必ずrevertです。resetで消すと、他の人の手元にある履歴と食い違い、収拾がつかなくなります。

退避する

git stash
git stash              # 変更を退避して、作業ツリーをきれいにする
git stash -u           # 未追跡(新規)ファイルも一緒に退避
git stash list         # 退避したものの一覧
git stash pop          # 最後に退避したものを戻す
git stash drop         # 退避したものを捨てる

-u を付ける場面が意外と多いです。既定のstashは、Gitがまだ知らない新規ファイルを退避しません。そのままpullすると「未追跡のファイルを上書きすることになるので中断する」と止められます。

stash は名前を付けられる

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回増やすだけで、事故の大きさが変わります。

共有する

やり取りの3つ
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

git 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 --shortgit diff --stat の2つを挟むだけで、「意図しないものが混ざっている」「意図したものが入っていない」の両方に気づけます。

最後に、止められたときは理由があること。pushの拒否も、ロックによる中断も、Gitが壊れないように守っている動作です。--force や強制削除で押し通す前に、なぜ止まったのかを読むほうが、結果的に速いです。

← ブログ一覧へ戻る