git add コマンド: cancel, all, ファイルディレクトリ, -u, -i オプション
git init コマンド に続いて、この記事では git add
コマンドについて説明します。
add
から commi
t までの git の仕組みや、生産性を上げるためのオプション、ステージしたファイルやディレクトリを元に戻す方法などについて説明します。
さらに詳しく知りたい人のために、最後に内部の仕組みについてもまとめておきます。
1. 追加からコミットまでの簡単な仕組み
1.1 git add と git commit の流れを理解する
git の仕組みに飛び込む前に、ここで考えておきたいことがあります。 新しいドキュメントを作成して保存する必要があるとしたら、私たちはいくつのステップを踏むでしょうか?
答えは簡単です。write -> save -> commit でドキュメントが保存されます。 これは単純だが、問題がある。たった一ステップなので、間違って保存してしまう可能性が高いのです。
Gitは一度の保存をとても大切にします。 そのため、一度の保存でミスをする可能性を最小限にするために、2つのステップを踏むのです。 その手順は次の通りです。
ファイルに変更が加えられたら、それを git add
コマンドでコミットします。
それから git commit
を実行し、ステージ状態にあるすべての変更をひとつのコミットとしてヒストリにコミットします。
コミットされたファイルに新しい変更が加えられると、そのファイルは別の git add
コマンドの対象となります。
これがバージョン管理の仕組みです: git add
-> git commit
-> ファイルの変更 -> git add
という流れです。
例を見て理解しましょう。
1.2 自分でやってみる git add と git commit の理解
まず、2つのマークダウンファイルが格納されているディレクトリを用意し、新しいレポを作成します。git status
コマンドで現在の状態を見ると、まだ追跡していないファイルが 2 つあります。
1.md
というファイルを git add コマンドでステージ状態に追加します。薄緑色で表示されている `1.md' ファイルの追跡が開始され、コミット待ちの状態になっています。
コマンド git commit -m "commit message"
でコミットを実行すると、ファイル 1.md
への変更が新しいコミットとして登録され、ステージ状態から消えます。
この時点で、1.md
ファイルに新しい変更があればステージ状態に戻ります。
このように、add
コマンドとcommit
コマンドが繰り返されます。
1.3 もう少し詳しく
Git は、作業フォルダ内のすべてのファイルやフォルダを、主に次の 2 つの状態で追跡しています。
untracked
: git はファイルへの変更を追跡していません。tracked
:gitはファイルの変更を追跡している。 git initコマンドで新しいレポジトリを作成したときは、すべてのファイルは未追跡の状態です。git add
コマンドはファイルを未追跡から追跡ありに変更し、変更を監視し続けます。
git は追跡済みのファイルを次の 3 つの状態のいずれかで保持します。
staged
: コミットになる準備をしている状態です。追跡されていない状態のファイルが最初に追跡された状態に変更されると、そのファイルはステージされた状態になります。変更状態のファイルもgit add
コマンドによってステージ状態になる。unmodified
: ステージ状態のファイルは、git commit
コマンドで変更がコミットされるとアンモディファイド状態になります。この状態は変更がなくなるまで維持されます。Modified
: 変更されていない状態のファイルは、変更が加えられると変更された状態になります。この状態のファイルはgit add
コマンドの対象となります。
すべての状態をまとめると、追跡されていない untracked --(git add
)--> tracked/staged --(git commit
)--> unmodified --(変更が発生した状態) --> staged となります。
2. git add -A あるいは --all コマンドを使ったすべてのファイルやフォルダの追加
上の例のように、現在の作業フォルダーの特定のファイルやフォルダーをステージするには、次のコマンドを使います。
git add <file 1>, <file 2>, <folder 1>
もし <folder 1>
の中にサブディレクトリがあれば、Git は自動的にそれらをまとめてステージ状態に追加します。
特定のファイルやフォルダを選択することなく、現在の作業フォルダ内のすべてのファイルやフォルダをステージしたい場合は、次のコマンドを使います。これは、追跡されていないファイルや変更されたファイルをすべて対象とします。
$ git add -A
または
$ git add .
3. git add -u による追跡ファイルやフォルダーの追加
Git が現在の作業フォルダーで追跡しているすべての変更されたファイルやフォルダーだけをステージするには、次のコマンドを使います。 セクション2のコマンドと比べると、追跡されていないファイルやフォルダは除外されます。
$ git add -u
4. git add -i コマンドで必要なファイルやフォルダを簡単に追加できる
次のコマンドで対話モードを開始すると、ステージしたいファイルだけを追加したり、単純な数字で削除したりすることができます。
$ git add -i
インタラクティブモードはこんな感じです。
対話モードでは、`git status' の出力とともにコマンドが表示されます。選択した内容にもよりますが、4は追跡されていないファイルをステージするのに使われ、2は変更されたファイルをステージするのに使われます。3 は 2 と 4 でステージされたファイルを元に戻すのに使います。
5. undo git add
対話モードに加えて、git add
コマンドで追加されたファイルやフォルダを元に戻すコマンドもあります。
作業フォルダー内の特定のファイルやフォルダーを元に戻すには、次のコマンドを使います。
git restore --staged <file 1>, <folder 1>
すべてのファイルとフォルダを復元するには、次のコマンドを使用します。
$ git restore --staged .
6. git add コマンドの内部動作
内部的には、Git はいくつかの重要なデータ構造と概念を使って変更を管理・追跡しています。 それでは、`git add' コマンドを実行したときに内部で何が起こるのかを順を追って見ていきましょう。
git add
コマンドを実行すると、Git は指定されたファイルの内容のスナップショットを取得し、Git のオブジェクトデータベース(.git/objects
にあります)に新しい blob オブジェクトを作成します。 blobオブジェクトはファイルの内容を表すもので、ファイルそのものを表すものではありません。- 次にGitはこのblobオブジェクトを参照して、ファイルのステージング領域(言い換えればインデックス)にエントリーを追加します。このエントリには、ファイルへのパス、モード(ファイルタイプとパーミッション)、そしてblobオブジェクトのSHA-1ハッシュが含まれます。 複数のファイルを追加する場合、Gitはファイルごとに個別のブロブ・オブジェクトとインデックス・エントリーを作成します。
- これで、インクリメンタルな変更をコミットする準備ができました。git commit' コマンドを実行すると、新しいコミットのディレクトリ構造とファイルの内容を表す新しいツリーオブジェクトが作成されます。 また、ツリーオブジェクトを指す新しいコミットオブジェクトを作成し、コミットのメタデータ (作者、日付、メッセージなど) を保存し、親コミットを指すようにします。
- 最後に、Git はブランチ参照 (master ブランチの場合は
refs/heads/master
など) を更新して新しいコミットオブジェクトを指すようにし、ブランチ履歴の最新のコミットとします。
まとめると、git add
コマンドを実行すると、追加されたファイルの blob オブジェクトが作成され、そのファイルの情報でステージングエリアが更新され、次のコミットの準備が行われます、
そして次のコミットの準備をします。コミット自体は git commit
を実行するまで作成されません。
7. 最後に
git add
コマンドは git バージョン管理システムの心臓部であり、その仕組みを理解するための多くの概念があります。
この記事で、git バージョン管理システムの背後にある概念と、ステージングを簡単にするためのさまざまなオプションについて理解していただけたと思います。
