Git入門:バージョン管理のきほん

変更を記録する(add と commit)

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部
commit はセーブポイント

このレッスンで分かること

  • git addgit commit を分けて実行する具体的な手順
  • コミットが 1 つ増えると git log の表示がどう変わるか
  • add を忘れた、余計なファイルを add した、というときの戻し方

前提を 30 秒で確認する

前のレッスンで扱った通り、ファイルはワークツリー・ステージ・リポジトリの 3 か所を移動します。git add がワークツリーからステージへ、git commit がステージからリポジトリへ運ぶ操作です。

プレーンテキスト

ワークツリー --git add--> ステージ --git commit--> リポジトリ

冒頭の図解にある通り、コミットは 1 つずつ鎖のようにつながって履歴になります。このレッスンでは、その鎖の最初の 3 つを実際に作ります。

作業は前レッスンで作った git-practice フォルダで続けます。

ターミナル

cd ~/git-practice git status

プレーンテキスト

On branch main No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) README.md nothing added to commit but untracked files present (use "git add" to track)

README.md が未追跡のまま残っている状態から始めます。無い場合は作り直してください。

ターミナル

echo "# Git practice" > README.md

git add でステージに乗せる

ファイル名を指定してステージに乗せます。

ターミナル

git add README.md

このコマンドは成功しても何も表示しません。Git は成功時に黙るコマンドが多く、これは正常な動作です。結果を確かめるには git status を使います。

ターミナル

git status

プレーンテキスト

On branch main No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: README.md

さきほどまで Untracked files にいた README.mdChanges to be committed に移りました。この見出しが「ステージにあるもの」を意味します。new file は、リポジトリにまだ存在しない新規ファイルだという表示です。

複数のファイルをまとめて乗せることもできます。

書き方対象
git add README.mdそのファイル 1 つ
git add README.md index.html指定した複数ファイル
git add src/そのディレクトリ配下すべて
git add .今いるディレクトリ配下すべて
git add -Aリポジトリ全体すべて

git add . は便利ですが、意図しないファイルまで巻き込みます。実行前に必ず git status で何が変更されているかを見る癖を付けてください。特にパスワードを書いた設定ファイルや、サイズの大きい生成物を誤ってコミットする事故は、ほぼ git add . から起きます。

git add は「追加」という語感ですが、実際には「今のこの内容をステージに写す」操作です。すでに追跡しているファイルを編集したときも git add を使います。新規と更新で別のコマンドがあるわけではありません。

ここで押さえておきたいのが、git addその瞬間の内容を写すという点です。git add したあとにもう一度そのファイルを編集すると、ステージには古い内容、ワークツリーには新しい内容が入った状態になります。git status では同じファイル名が Changes to be committedChanges not staged for commit の両方に出ます。

プレーンテキスト

Changes to be committed: modified: README.md Changes not staged for commit: modified: README.md

この状態でコミットすると、記録されるのはステージにある古いほうです。「直したはずの修正が入っていない」という混乱の正体はこれです。編集したら git add をやり直す、と覚えておけば防げます。

git commit で履歴に刻む

ステージに乗ったものを記録します。

ターミナル

git commit -m "初回コミット"

プレーンテキスト

[main (root-commit) 8f3d2a1] 初回コミット 1 file changed, 1 insertion(+) create mode 100644 README.md

-m はメッセージをその場で指定するオプションです。付けない場合はエディタが開き、そこにメッセージを書いて保存・終了するとコミットされます。

出力の読み方は次の通りです。main は今いるブランチ名、root-commit は履歴の 1 件目であることを示す印、8f3d2a1 がこのコミットのIDです。1 file changed, 1 insertion(+) は 1 ファイルに 1 行追加されたという集計です。

もう一度 git status を見ます。

ターミナル

git status

プレーンテキスト

On branch main nothing to commit, working tree clean

nothing to commit, working tree clean は、ワークツリーとステージとリポジトリの 3 つが完全に一致している状態を表します。この表示が出ていれば、記録されていない変更は 1 つもありません。作業の区切りでこの状態を作るのが基本の進め方です。

履歴を確認します。

ターミナル

git log --oneline

プレーンテキスト

8f3d2a1 (HEAD -> main) 初回コミット

HEAD -> main は「今いる場所が main ブランチで、その先端がこのコミット」という意味です。git log の詳しい読み方は次々回のレッスンで扱います。

2 つめ、3 つめのコミットを積む

ファイルを 1 つ増やし、既存のファイルも編集して、変更が 2 種類ある状態を作ります。

ターミナル

echo "console.log('hello');" > app.js echo "Git の練習用リポジトリです。" >> README.md git status

プレーンテキスト

On branch main Changes 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.md Untracked files: (use "git add <file>..." to include in what will be committed) app.js no changes added to commit (use "git add" and/or "git commit -a")

見出しが 2 つに分かれました。Changes not staged for commit は追跡済みだが編集されただけのファイル、Untracked files はまだ一度も記録していないファイルです。

ここで 2 つを別々のコミットにしてみます。まず app.js だけを記録します。

ターミナル

git add app.js git commit -m "hello を出力するスクリプトを追加"

プレーンテキスト

[main 4b7e903] hello を出力するスクリプトを追加 1 file changed, 1 insertion(+) create mode 100644 app.js

続いて README.md を記録します。

ターミナル

git add README.md git commit -m "README にリポジトリの説明を追記"

プレーンテキスト

[main c1a5f22] README にリポジトリの説明を追記 1 file changed, 1 insertion(+)

2 件目以降には root-commit の表示が付きません。親コミットを持つ普通のコミットだからです。

ターミナル

git log --oneline

プレーンテキスト

c1a5f22 (HEAD -> main) README にリポジトリの説明を追記 4b7e903 hello を出力するスクリプトを追加 8f3d2a1 初回コミット

新しいものが上に並びます。冒頭の図解と同じ形で、3 つのコミットが鎖になりました。

追跡済みファイルの編集だけをコミットしたいときは git commit -am "メッセージ"add を省略できます。ただし未追跡ファイルは対象外なので、新規ファイルは含まれません。この落とし穴があるため、慣れるまでは addcommit を分けて打つことを勧めます。

メッセージの書き方の最低限

コミットメッセージには決まった正解がありませんが、最初に守るべき点は 3 つです。

1 つめは、何をしたかを書くことです。「修正」「更新」だけでは 1 週間後の自分に何も伝わりません。「ログインボタンが押せない不具合を修正」まで書きます。

2 つめは、1 行目を 50 文字程度に収めることです。多くのツールが 1 行目だけを一覧に表示するため、長いと途中で切れます。詳しい説明が要るときは、1 行空けてから 2 行目以降に書きます。

3 つめは、日本語で書いて構わないということです。チームの方針が英語でない限り、正確に伝わるほうが優先されます。

よく見かける形として、先頭に種類を示す短い語を置く書き方があります。

先頭の語使う場面
feat新しい機能を足した
fix不具合を直した
docsドキュメントだけを直した
refactor動きは変えずに書き方を整えた
testテストを足した、直した

この書き方に従うと fix: ログインボタンが押せない不具合を修正 のようになります。慣習として広く使われているので、他人のリポジトリを読むときに知っておくと役に立ちます。個人の練習では必須ではありません。

複数行のメッセージは -m を重ねて書けます。

ターミナル

git commit -m "検索フォームの入力チェックを追加" -m "空文字と全角スペースだけの入力を弾くようにした。既存の検索処理には影響しない。"

書き方の詳細は第 2 章の良いコミットメッセージの書き方で扱います。

ありがちな失敗と戻し方

add を忘れてコミットした

git add を打たずに git commit すると、Git は記録するものが無いと言って止まります。

プレーンテキスト

On branch main Changes not staged for commit: modified: README.md no changes added to commit

このメッセージが出たら、単に git add を打ってからやり直せば済みます。何も壊れていません。

厄介なのは、複数ファイルを直したのに 1 つしか add していない場合です。コミットは成功しますが、中身が欠けています。出力の 1 file changed が期待と違ったら、その場で気付けます。忘れたファイルを追加して git commit --amend で直前のコミットに含める方法が第 2 章にあります。

余計なファイルを add した

まだコミットしていないなら、ステージから降ろすだけで済みます。

ターミナル

git restore --staged secret.txt

このコマンドはステージから外すだけで、ワークツリーの中身には触れません。ファイルが消えることはないので安心して実行できます。

git status の案内には git rm --cached と出ることもあります。こちらは未追跡の状態に戻す操作で、新規ファイルをステージから外す場合はどちらでも同じ結果になります。

変更を全部消したくなった

編集内容そのものを捨てて、最後のコミットの状態に戻したい場合は次を使います。

ターミナル

git restore README.md

これは編集内容を消す操作なので、実行すると元に戻せません。まだコミットしていない変更は Git のどこにも残っていないからです。実行前に本当に捨ててよいか確認します。詳しい挙動は第 2 章の変更を取り消す(restore)で扱います。

次のレッスンでは git statusgit diff を使い、いま何がどう変わっているのかを正確に読む方法を身につけます。この 2 つが読めるようになると、add する前に中身を確認できるので事故が激減します。

この章のポイント
  • git add はステージに写す操作、git commit はステージの内容を履歴に刻む操作
  • git commit -m の出力に出る 1 file changed は、意図した数と合っているか毎回確認する
  • nothing to commit, working tree clean は 3 か所が一致している安全な状態
  • ステージから降ろすのは git restore --staged、編集を捨てるのは git restore