minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

ファイルの変更

では、先ほどコミットしたファイルに変更を加えてみます。

$ echo "hello world2" >> file1

file1 の末尾に1行追加しました。
すぐコミットしてみましょう。

$ git commit -m "second commit"
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   file1
#
no changes added to commit (use "git add" and/or "git commit -a")

はて、変ですね。どうやらコミットは行われなかったようです。
ここも SVN と大きく異なるところです。

Git では、一度 add したファイルもそのファイルを次にコミットするときにはその都度 add によって加えなければなりません
詳しい理由は後から説明しますので、今はそういうものなんだと理解しておいて下さい。
ちなみに上のメッセージは、この時点で git status とやっても同じものが表示されます。

とりあえず、再度 add してみましょう。

$ git add .
$ git status
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   file1

これでコミットする準備ができました。
ではコミットしましょう。

$ git commit -m "second commit"
[master fdb8b88] second commit
 1 files changed, 1 insertions(+), 0 deletions(-)

無事、コミットが完了しました。

ここまで来て、あることに気付いたでしょうか。
そう、SVN ではおなじみの「リビジョン番号」が出てきていません。

Git には、リビジョン番号という概念が無いのです。
その代わりに、先ほど紹介したIDのようなものでコミットを管理します。
これは「ハッシュ値」と呼ばれます。
リビジョン番号とは異なり、コミットする度に値が増えていくわけではありません。

ステージ

先ほどのメッセージで以下のようなものがありました。

Changes not staged for commit

これはどういう意味でしょう?
stage とは「舞台にのせる」という意味です。

つまり「変更が、コミットするための舞台にのせられていない」と言っているのです。
ファイルは変更したけどまだ add されてないよ、ってことです。

Git には、ファイルには以下の状態があります。

git diff

ではここで、まだ紹介していなかった git diff コマンドを使ってみましょう。
まずはファイルの内容を変更します。

$ echo "hello world3" >> file1

ここで早速 diff コマンド。

$ git diff
diff --git a/file1 b/file1
index 5062e73..674e424 100644
--- a/file1
+++ b/file1
@@ -1,2 +1,3 @@
 hello world
 hello world2
+hello world3

このように、diff 結果が表示されました。
これは当たり前のように思われるかもしれませんが、先ほどの状態一覧と照らし合わせてみると
もう少し詳しいことがわかります。
つまり、この diff は「前回コミットされた内容」と「今回変更してまだ add していない内容」を比較しているのです。

試しに add してから diff を実行してみましょう。

$ git add .
$ git diff

このとき、diff は何も表示しません。つまり、「差分が無い」と言っているのです。

Git のマニュアルを見ると、git diff コマンドの説明が以下のように書いてあります。
show diff of unstaged changes
そう、git diff は「まだステージに上げられていない変更」を表示するコマンドなのです。
ステージに上がっているか上がっていないかというのは、Git では重要な違いであり
意識する必要があるということです。
変更後ステージに上げると、それはもはや仮コミットされたと見なされ diff の表示対象ではなくなります。

ステージに上げる前

変更したが、まだ検証できていない状態。
画面上では赤色で表示される。

ステージに上げた後

変更後、内容が検証され「コミットしてOK」となった状態。
画面上では緑色で表示される。

SVN では、ローカルで変更した内容を誤ってリポジトリにコミットしてしまうなんてことがよくあります。
Git はこれを回避するために、ステージという概念を用いているのです。

では、ステージに上げられた変更を見るときはどうするのでしょうか。

$ git diff --cached

このように、--cached オプションを付けます。
これは「ステージに上げられた変更」を表示します。

これらは同じ diff コマンドですが、単なるオプションを付ける付けない以上の大きな差があります。
別コマンドと考えておいた方がいいでしょう。

git diff

まだステージに上げられていない変更を表示する。
自分がローカルで変更した内容を知りたいときに使う。

git diff --cached

ステージに上げられた変更を表示する。
自分がこれからコミットしようとしている内容を知りたいときに使う。

SVN を使っていると、よくこんなことがあります。

Git は、変更を積極的にすることをユーザに奨めています。
「ステージに上げない限りは変更しても安心だよ」と言っているのです。
また、「コミットするときには明確にその対象を把握して下さいね」とも言っています。
作業中、コミットする必要があるファイルを随時ステージに上げておけば、次のコミット時に
どれをコミットしていいか迷う必要も無くなります。

Git は Linux カーネルという膨大なコード量と作業人数を持ったプロジェクトのために誕生しました。
大人数で一つのリポジトリを適切に扱うために、ステージという舞台が用意されたのでしょう。

index(索引)

先ほど、Git では 一度 add したファイルも
そのファイルを次にコミットするときにはその都度 add によって加えなければなりません、と書きました。
これを詳しく説明しましょう。

add するとそのファイルはステージに上げられるということは既に説明しました。
では具体的には、どうやっているのでしょう?

add すると、Git は index と呼ばれる索引にそのファイルを登録します。
索引に登録されたファイルは「ステージに上がった」ことになり、
これは「次にコミットするときの対象である」ことを明確にします。

まだバージョン管理対象(track)になっていないファイルを管理対象にするときにも
add を使います。このとき、add は

という二つの処理を行います。
既に管理対象になっているファイルに対して add を使うと、ステージに上げる処理だけが行われます。

また、一度変更して add した後、再度そのファイルを変更すると
そのファイルは「ステージから引きずり降ろされます」。
なぜならそのファイルは、あなたが「ステージに上がって良し」と頷いて add コマンドを実行した後で
別の変更を加えてしまったのですから。
再びステージに上げるためには、再度 add する必要があります。

add と commit を同時に行う

ここまで敢えて説明してきませんでしたが、Git には add と commit を同時に行うコマンドが用意されています。
それが git commit -a です。

Git のマニュアルには以下のようにあります。
automatically stage all tracked, modified files before the commit
自動的に全ての変更されたファイル(管理対象外ファイルは除く)をステージに上げ、コミットする。

このコマンド(オプション)を使えば、SVN と同じ感覚で commit を使うことができます。
しかし Git を使うのであれば、このオプションは使わないことをオススメします。
ちゃんと add してコミット対象を把握してから、commit しましょう。