セットアップと設定
プロジェクトの取得と作成
基本的なスナップショット
ブランチとマージ
プロジェクトの共有と更新
検査と比較
パッチ適用
デバッグ
メール
外部システム
サーバー管理
- 2.23.1 → 2.50.1 変更なし
-
2.23.0
2019-08-16
- 2.13.7 → 2.22.5 変更なし
-
2.12.5
2017-09-22
- 2.3.10 → 2.11.4 変更なし
-
2.2.3
2015-09-04
- 2.1.4 変更なし
-
2.0.5
2014-12-17
説明
このチュートリアルを読む前に、gittutorial[7] を完了しておく必要があります。
このチュートリアルの目的は、Gitのアーキテクチャの2つの基本的な部分、すなわちオブジェクトデータベースとインデックスファイルを紹介し、読者がGitドキュメントの残りの部分を理解するために必要なすべてを提供することです。
Gitオブジェクトデータベース
新しいプロジェクトを開始し、少し履歴を作成してみましょう。
$ mkdir test-project $ cd test-project $ git init Initialized empty Git repository in .git/ $ echo 'hello world' > file.txt $ git add . $ git commit -a -m "initial commit" [master (root-commit) 54196cc] initial commit 1 file changed, 1 insertion(+) create mode 100644 file.txt $ echo 'hello world!' >file.txt $ git commit -a -m "add emphasis" [master c4d59f3] add emphasis 1 file changed, 1 insertion(+), 1 deletion(-)
Gitがコミットに対して応答した7桁の16進数は何でしたか?
チュートリアルのパート1で、コミットがこのような名前を持つことを見ました。Git履歴のすべてのオブジェクトは、40桁の16進数名で保存されています。その名前は、オブジェクトの内容のSHA-1ハッシュです。これにより、Gitは同じデータを2度保存することはありません(同一のデータには同一のSHA-1名が与えられるため)、またGitオブジェクトの内容が変更されることもありません(変更するとオブジェクトの名前も変わるため)ことが保証されます。ここにある7文字の16進数文字列は、そのような40文字の長い文字列の単なる略語です。略語は、曖昧でなければ、40文字の文字列が使用できるすべての場所で使用できます。
上記の例に従って作成したコミットオブジェクトの内容は、作成された時刻とコミットを実行した人物の名前を記録するため、上記に示されているものとは異なるSHA-1ハッシュを生成することが予想されます。
cat-file
コマンドを使って、この特定のオブジェクトについてGitに問い合わせることができます。この例の40桁の16進数をコピーせず、自分のバージョンからのものを使用してください。40桁すべてを入力する手間を省くために、数文字に短縮できることに注意してください。
$ git cat-file -t 54196cc2 commit $ git cat-file commit 54196cc2 tree 92b8b694ffb1675e5975148e1121810081dbdffe author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500 committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500 initial commit
ツリーは1つ以上の「ブロブ」オブジェクトを参照できます。それぞれが1つのファイルに対応します。さらに、ツリーは他のツリーオブジェクトも参照でき、これによりディレクトリ階層を作成します。ls-treeを使用して任意のツリーの内容を調べることができます(SHA-1の十分長い最初の部分でも機能することを忘れないでください)。
$ git ls-tree 92b8b694 100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad file.txt
したがって、このツリーには1つのファイルが含まれていることがわかります。SHA-1ハッシュは、そのファイルのデータへの参照です。
$ git cat-file -t 3b18e512 blob
「ブロブ」は単なるファイルデータであり、これもcat-fileで調べることができます。
$ git cat-file blob 3b18e512 hello world
これは古いファイルデータであることに注意してください。つまり、Gitが最初のツリーへの応答で名前を付けたオブジェクトは、最初のコミットによって記録されたディレクトリの状態のスナップショットを持つツリーでした。
これらのオブジェクトはすべて、Gitディレクトリ内にSHA-1名で格納されます。
$ find .git/objects/ .git/objects/ .git/objects/pack .git/objects/info .git/objects/3b .git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad .git/objects/92 .git/objects/92/b8b694ffb1675e5975148e1121810081dbdffe .git/objects/54 .git/objects/54/196cc2703dc165cbd373a65a4dcf22d50ae7f7 .git/objects/a0 .git/objects/a0/423896973644771497bdc03eb99d5281615b51 .git/objects/d0 .git/objects/d0/492b368b66bdabf2ac1fd8c92b39d3db916e59 .git/objects/c4 .git/objects/c4/d59f390b9cfd4318117afde11d601c1085f241
そして、これらのファイルの内容は、圧縮されたデータと、その長さとタイプを識別するヘッダーのみです。タイプは、ブロブ、ツリー、コミット、またはタグのいずれかです。
最も見つけやすいコミットはHEADコミットで、.git/HEAD から見つけることができます。
$ cat .git/HEAD ref: refs/heads/master
ご覧のとおり、これは現在どのブランチにいるかを教えてくれます。これは、.gitディレクトリの下にあるファイルを指定することで、それを伝えます。そのファイル自体には、コミットオブジェクトを参照するSHA-1名が含まれており、それをcat-fileで調べることができます。
$ cat .git/refs/heads/master c4d59f390b9cfd4318117afde11d601c1085f241 $ git cat-file -t c4d59f39 commit $ git cat-file commit c4d59f39 tree d0492b368b66bdabf2ac1fd8c92b39d3db916e59 parent 54196cc2703dc165cbd373a65a4dcf22d50ae7f7 author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500 committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500 add emphasis
ここでの「ツリー」オブジェクトは、ツリーの新しい状態を指します。
$ git ls-tree d0492b36 100644 blob a0423896973644771497bdc03eb99d5281615b51 file.txt $ git cat-file blob a0423896 hello world!
そして「親」オブジェクトは、前のコミットを指します。
$ git cat-file commit 54196cc2 tree 92b8b694ffb1675e5975148e1121810081dbdffe author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500 committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500 initial commit
ツリーオブジェクトは最初に調べたツリーであり、このコミットは親を持たないという点で珍しいものです。
ほとんどのコミットは親を1つだけ持ちますが、複数の親を持つコミットも一般的です。その場合、コミットはマージを表し、親参照はマージされたブランチのヘッドを指します。
ブロブ、ツリー、コミット以外に、残りのオブジェクトタイプは「タグ」のみですが、ここでは説明しません。詳細はgit-tag[1]を参照してください。
これで、Gitがオブジェクトデータベースを使用してプロジェクトの履歴をどのように表現するかを理解しました。
-
「コミット」オブジェクトは、履歴の特定の時点におけるディレクトリツリーのスナップショットを表す「ツリー」オブジェクトを参照し、プロジェクト履歴への接続方法を示すために「親」コミットを参照します。
-
「ツリー」オブジェクトは、単一ディレクトリの状態を表し、ファイルデータを含む「ブロブ」オブジェクトと、サブディレクトリ情報を含む「ツリー」オブジェクトにディレクトリ名を関連付けます。
-
「ブロブ」オブジェクトは、他の構造を持たないファイルデータを含んでいます。
-
各ブランチの先頭にあるコミットオブジェクトへの参照は、.git/refs/heads/ の下のファイルに保存されます。
-
現在のブランチの名前は .git/HEAD に保存されます。
ちなみに、多くのコマンドがツリーを引数として受け取ることに注意してください。しかし、上記で見たように、ツリーは多くの異なる方法で参照できます。そのツリーのSHA-1名、そのツリーを参照するコミットの名前、そのツリーを参照するヘッドを持つブランチの名前などです。そして、ほとんどのそのようなコマンドは、これらの名前のいずれかを受け入れることができます。
コマンドの概要では、「tree-ish」という単語がそのような引数を指定するために使用されることがあります。
インデックスファイル
コミットを作成するために使用してきた主なツールは git-commit
-a
で、これは作業ツリーに行ったすべての変更を含むコミットを作成します。しかし、特定のファイルへの変更のみをコミットしたい場合はどうでしょうか?または、特定のファイルへの特定の変更のみをコミットしたい場合は?
コミットがどのように作成されるかを見ると、より柔軟なコミット作成方法があることがわかります。
引き続きテストプロジェクトで、file.txt をもう一度変更してみましょう。
$ echo "hello world, again" >>file.txt
ただし今回は、すぐにコミットするのではなく、中間ステップを踏み、何が起こっているかを追跡するために、途中で差分を要求してみましょう。
$ git diff --- a/file.txt +++ b/file.txt @@ -1 +1,2 @@ hello world! +hello world, again $ git add file.txt $ git diff
最後の差分は空ですが、新しいコミットは作成されておらず、ヘッドにはまだ新しい行が含まれていません。
$ git diff HEAD diff --git a/file.txt b/file.txt index a042389..513feba 100644 --- a/file.txt +++ b/file.txt @@ -1 +1,2 @@ hello world! +hello world, again
したがって、*git diff* はヘッド以外の何かと比較しています。比較対象は実際にはインデックスファイルで、バイナリ形式で .git/index に保存されていますが、その内容は ls-files で調べることができます。
$ git ls-files --stage 100644 513feba2e53ebbd2532419ded848ba19de88ba00 0 file.txt $ git cat-file -t 513feba2 blob $ git cat-file blob 513feba2 hello world! hello world, again
したがって、*git add* が行ったことは、新しいブロブを保存し、それをインデックスファイルに参照として置いたことです。ファイルを再度変更すると、新しい変更が *git diff* の出力に反映されることがわかります。
$ echo 'again?' >>file.txt $ git diff index 513feba..ba3da7b 100644 --- a/file.txt +++ b/file.txt @@ -1,2 +1,3 @@ hello world! hello world, again +again?
適切な引数を使用すると、*git diff* は作業ディレクトリと最後のコミットとの差分、またはインデックスと最後のコミットとの差分も表示できます。
$ git diff HEAD diff --git a/file.txt b/file.txt index a042389..ba3da7b 100644 --- a/file.txt +++ b/file.txt @@ -1 +1,3 @@ hello world! +hello world, again +again? $ git diff --cached diff --git a/file.txt b/file.txt index a042389..513feba 100644 --- a/file.txt +++ b/file.txt @@ -1 +1,2 @@ hello world! +hello world, again
いつでも、git commit(「-a」オプションなし)を使用して新しいコミットを作成し、コミットされた状態がインデックスファイルに保存されている変更のみを含み、まだ作業ツリーにのみ存在する追加の変更は含まれないことを確認できます。
$ git commit -m "repeat" $ git diff HEAD diff --git a/file.txt b/file.txt index 513feba..ba3da7b 100644 --- a/file.txt +++ b/file.txt @@ -1,2 +1,3 @@ hello world! hello world, again +again?
したがって、デフォルトでは *git commit* は作業ツリーではなくインデックスを使用してコミットを作成します。コミットの「-a」オプションは、まず作業ツリーのすべての変更でインデックスを更新するように指示します。
最後に、*git add* がインデックスファイルに与える影響を見てみる価値があります。
$ echo "goodbye, world" >closing.txt $ git add closing.txt
*git add* の効果は、インデックスファイルに1つのエントリを追加することでした。
$ git ls-files --stage 100644 8b9743b20d4b15be3955fc8d5cd2b09cd2336138 0 closing.txt 100644 513feba2e53ebbd2532419ded848ba19de88ba00 0 file.txt
そして、cat-file で確認できるように、この新しいエントリはファイルの現在の内容を参照しています。
$ git cat-file blob 8b9743b2 goodbye, world
「status」コマンドは、状況の概要を素早く把握するのに便利な方法です。
$ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: closing.txt 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: file.txt
closing.txt の現在の状態はインデックスファイルにキャッシュされているため、「Changes to be committed」としてリストされます。file.txt には作業ディレクトリに変更があり、それらがインデックスに反映されていないため、「changed but not updated」とマークされます。この時点で「git commit」を実行すると、closing.txt が(新しい内容で)追加されますが、file.txt は変更されないコミットが作成されます。
また、単なる git
diff
は file.txt への変更を表示しますが、closing.txt の追加は表示しません。これは、インデックスファイル内の closing.txt のバージョンが、作業ディレクトリ内のものと同一であるためです。
インデックスファイルは、新しいコミットのステージングエリアであるだけでなく、ブランチをチェックアウトするときにオブジェクトデータベースから入力され、マージ操作に関与するツリーを保持するために使用されます。詳細については、gitcore-tutorial[7] および関連するマニュアルページを参照してください。
次は何を?
この時点で、Gitコマンドのマニュアルページを読むのに必要なすべてを理解しているはずです。最初に読むのに良い場所は、giteveryday[7] で言及されているコマンドでしょう。gitglossary[7] で、知らない専門用語を見つけることができるはずです。
Gitユーザーマニュアル は、Gitへのより包括的な入門書です。
gitcvs-migration[7] は、CVSリポジトリをGitにインポートする方法を説明し、CVSのような方法でGitを使用する方法を示しています。
Gitの使用例については、ハウツー を参照してください。
Git開発者向けには、gitcore-tutorial[7] が、たとえば新しいコミットの作成など、下位レベルのGitメカニズムについて詳しく説明しています。
GIT
git[1]スイートの一部