status・diff・add を理解する — Git Tips
編集しただけでは履歴に残りません。記録までの状態は作業ツリー → ステージ → コミット済みの3段で、行き来する道具が status / diff / add です。
参考(公式)
目次
作業ツリーとステージとコミット済みの違い
Git を使ったファイルは、常にこの 3 つの状態のどこかにあります。
| 状態 | 別名 | 内容 |
|---|---|---|
| 作業ツリー | Working Directory | 実際にエディタで編集しているファイルそのもの |
| ステージ | Index / Staging Area | 次の commit に含める予定として登録した内容 |
| コミット済み | Repository | git commit によって履歴に記録された状態 |
作業ツリー --git add--> ステージ --git commit--> コミット済み ^ | |-- git restore <file> --| (作業ツリーをステージの内容で上書き) |コミット済み -- git restore --staged --> ステージ(ステージだけ取り消す。作業ツリーの編集内容は残る)編集した直後のファイルは「作業ツリー」にしかない変更です。git add を実行すると、その時点の内容が「ステージ」というスナップショットの下書きに載ります。git commit を実行すると、ステージの内容がそのまま履歴に記録されます。
このワンクッションがあることで、編集した内容のうち一部だけを次の commit に含めるといった柔軟な運用ができます。
git status で全体を見る
いま、どのファイルがどの状態にあるかを一覧で確認するコマンドです。
git status期待する出力の例(何も変更していないとき)
On branch mainnothing to commit, working tree cleanファイルを編集した直後の出力の例
echo "追記しました" >> README.mdgit statusOn branch mainChanges not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: README.mdno changes added to commit (use "git add" and/or "git commit -a")git status は基本的に 常に実行して困らないコマンド です。git add や git commit の前に一度打っておくだけで、意図しないファイルまで commit する事故を減らせます。表示を簡潔にしたい場合は -s(short)オプションも使えます。
git status -s M README.mdgit diff で変更内容を見る
git status は「どのファイルが変わったか」を教えてくれますが、「何が」変わったかは git diff で確認します。
作業ツリーとステージの差分
まだ git add していない変更(作業ツリー ↔ ステージ)を見る、最もよく使う形です。
git diff期待する出力の例
diff --git a/README.md b/README.mdindex e1a2b3c..f4d5e6a 100644--- a/README.md+++ b/README.md@@ -1 +1,2 @@ # practice-repo+追記しました行頭の + が追加された行、- が削除された行です。
ステージ済みの差分
git add した後、まだ commit していない内容(ステージ ↔ 直前のコミット)を見るには --staged(--cached でも同じ)を付けます。
git add README.mdgit diff --stagedgit diff(オプション無し)は ステージに載せた分は表示しません。「なぜ git add したのに git diff に何も出ない」と感じたら、それはステージ済みになった証拠で、git diff --staged を使えば見えます。
| コマンド | 比較対象 |
|---|---|
git diff |
作業ツリー ↔ ステージ(未ステージの変更) |
git diff --staged |
ステージ ↔ 直前のコミット(ステージ済みの変更) |
git diff HEAD |
作業ツリー ↔ 直前のコミット(ステージ済み・未ステージ両方) |
git add でステージする
変更を次の commit に含めるには git add でステージに載せます。
git add README.md複数ファイル、またはフォルダごと載せることもできます。
git add file1.txt file2.txtgit add .git add . は 今いるディレクトリとその配下すべての変更をステージする、という意味です。手早く進めたいときに便利ですが、意図しないファイル(一時ファイルやビルド生成物など)まで含めてしまう危険もあります。git status で対象を確認してから git add . を実行する、または個別にファイル名を指定する方が安全です。
| コマンド | 対象 |
|---|---|
git add ファイル名 |
指定した 1 つのファイルだけ |
git add フォルダ名 |
指定フォルダ配下のすべての変更 |
git add . |
カレントディレクトリ配下のすべての変更 |
git add -p |
変更をひとかたまりずつ確認しながら選んでステージ(対話的) |
ステージを取り消す
「git add したけど、まだ commit したくない」というときは、ステージから外すだけならファイルの内容自体は失われません。
現在の Git(2.23 以降)では git restore を使います。
git restore --staged README.mdこれでステージからは外れますが、作業ツリーの変更内容(編集した中身)はそのまま残ります。もう一度 git status を確認すると、Changes not staged for commit に戻っていることが分かります。
古いバージョンの Git や、他の記事・書籍で見かける書き方として git reset HEAD README.md もあります。動作はほぼ同じですが、git restore --staged の方が「ステージを操作している」という意図が名前から分かりやすいため、これから覚えるなら restore の方を優先してよいです。
作業ツリーの変更そのものを 捨てる(編集前に戻す)場合は、ステージの取り消しとは別のコマンドになります。
git restore README.mdこちらは編集内容自体を元に戻すため、保存していない変更は失われます。実行前に git diff で内容を確認しておくと安全です。
手元で一通り試す
ここまでのコマンドを、通しで一度実行してみます。
echo "1行目" > demo.txtgit status # Untracked files に demo.txtgit add demo.txtgit status # Changes to be committed に demo.txtgit diff --staged # 追加した内容が + で表示されるecho "2行目" >> demo.txtgit status # 同じファイルが staged と not staged の両方に出るgit diff # 2行目の追加だけが表示される(1行目は既にステージ済み)git add demo.txtgit commit -m "Add demo.txt"git status # nothing to commit, working tree clean同じファイルでも、ステージした時点の内容とその後さらに編集した内容が別々に扱われる点が、このシーケンスの理解しやすいポイントです。git diff は「まだステージしていない差分」だけを見ている、という原則を思い出すと混乱しにくくなります。
詰まりやすい点
git add . したら見せたくないファイルまで入ってしまった
すでに commit してしまった場合は ステージを取り消す の git restore --staged でステージから外せます。commit 前であれば同様に外してから、.gitignore に対象を追加しておくと再発を防げます。
# .gitignore の例node_modules/*.log.envgit diff で何も表示されない
すでに git add している変更は git diff(オプション無し)には出ません。git diff --staged を試してください。両方に何も出ない場合は、そもそも変更が保存されていない(エディタで保存し忘れている)可能性があります。
git restore が error: pathspec ... did not match any file(s) になる
ファイル名の指定を誤っている、またはそのファイルが Git の管理下に一度も入っていない(git add されたことがない)場合に出ます。git status で正確なファイル名を確認してから再実行してください。
変更を捨てるつもりで git restore --staged しか実行していない
git restore --staged は ステージから外すだけ で、作業ツリーの編集内容は残ります。編集内容自体を元に戻したい場合は、続けて git restore ファイル名 を実行する必要があります。
git status の表示が英語で読みにくい
git status はデフォルトでヒント(use "git add <file>..." ... のような行)も一緒に表示します。ヒントを消して簡潔にしたい場合は git status -s を使うと、状態を示す短い記号だけの一覧になります。