Git
英語 ▾ トピック ▾ 最新バージョン ▾ gittutorial-2 は2.23.0で最終更新されました

名前

gittutorial-2 - Git入門チュートリアル:パート2

概要

git *

説明

このチュートリアルを読む前に、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桁の16進数をすべて入力する手間を省くために、数文字に短縮できます

$ 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つ以上の「blob」オブジェクトを参照できます。さらに、ツリーは他のツリーオブジェクトも参照できるため、ディレクトリ階層を作成できます。 ls-treeを使用して、任意のツリーの内容を確認できます(SHA-1の最初の部分が十分に長ければ機能することに注意してください)

$ git ls-tree 92b8b694
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    file.txt

したがって、このツリーには1つのファイルが含まれていることがわかります。SHA-1ハッシュは、そのファイルのデータへの参照です

$ git cat-file -t 3b18e512
blob

「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

これらのファイルの内容は、圧縮データと、その長さと種類を識別するヘッダーだけです。種類は、blob、tree、commit、またはtagのいずれかです。

最も簡単なコミットはHEADコミットであり、.git/HEADから見つけることができます

$ cat .git/HEAD
ref: refs/heads/master

ご覧のとおり、これは現在どのブランチにいるかを示しており、.gitディレクトリの下のファイルに名前を付けることでこれを示しています。.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

ここでの「tree」オブジェクトは、ツリーの新しい状態を参照しています

$ git ls-tree d0492b36
100644 blob a0423896973644771497bdc03eb99d5281615b51    file.txt
$ git cat-file blob a0423896
hello world!

「parent」オブジェクトは、前のコミットを参照しています

$ 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

ツリーオブジェクトは最初に調べたツリーであり、このコミットは親がないという点で unusual です。

ほとんどのコミットには親が1つだけですが、コミットに複数の親があることもよくあります。その場合、コミットはマージを表し、親参照はマージされたブランチのヘッドを指します。

blob、tree、commitに加えて、残りのオブジェクトの種類は「tag」だけです。ここでは説明しません。詳細については、git-tag[1] を参照してください。

これで、Gitがオブジェクトデータベースを使用してプロジェクトの履歴を表す方法がわかりました

  • 「commit」オブジェクトは、履歴のある時点でのディレクトリツリーのスナップショットを表す「tree」オブジェクトを参照し、「parent」コミットを参照して、プロジェクト履歴にどのように接続されているかを示します。

  • 「tree」オブジェクトは、単一のディレクトリの状態を表し、ディレクトリ名をファイルデータを含む「blob」オブジェクトとサブディレクトリ情報を含む「tree」オブジェクトに関連付けます。

  • 「blob」オブジェクトには、他の構造のないファイルデータが含まれています。

  • 各ブランチのヘッドにあるコミットオブジェクトへの参照は、.git/refs/heads/の下のファイルに保存されます。

  • 現在のブランチの名前は.git/HEADに保存されます。

ちなみに、多くのコマンドは引数としてツリーを取ります。しかし、上記でわかるように、ツリーは多くの異なる方法で参照できます。ツリーのSHA-1名、ツリーを参照するコミットの名前、ヘッドがそのツリーを参照するブランチの名前などです。そして、そのようなコマンドのほとんどは、これらの名前のいずれかを受け入れることができます。

コマンドの概要では、「tree-ish」という言葉がそのような引数を指定するために使用されることがあります。

インデックスファイル

コミットを作成するために使用してきた主要なツールはgit-commit -aであり、作業ツリーに加えたすべての変更を含むコミットを作成します。しかし、特定のファイルへの変更のみをコミットしたい場合はどうでしょうか?または、特定のファイルへの特定の変更のみをコミットしたい場合はどうでしょうか?

コミットが内部でどのように作成されるかを見てみると、コミットを作成するより柔軟な方法があることがわかります。

テストプロジェクトを続行して、file.txtをもう一度変更してみましょう

$ echo "hello world, again" >>file.txt

しかし、今回はすぐにコミットする代わりに、中間ステップを実行し、何が起こっているかを追跡するためにdiffを要求してみましょう

$ git diff
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
 hello world!
+hello world, again
$ git add file.txt
$ git diff

最後の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_が行ったのは、新しいblobを保存し、インデックスファイルにその参照を配置することでした。ファイルをもう一度変更すると、新しい変更が_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_は作業ツリーではなくインデックスを使用してコミットを作成します。 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の現在の状態はインデックスファイルにキャッシュされているため、「コミットされる変更」としてリストされます。 file.txtにはインデックスに反映されていない作業ディレクトリの変更があるため、「変更されたが更新されていない」とマークされています。この時点で、「git commit」を実行すると、closing.txt(新しい内容を含む)が追加されますが、file.txtは変更されないコミットが作成されます。

また、ベアな_git diff_はfile.txtへの変更を表示しますが、closing.txtの追加は表示しません。これは、インデックスファイルのclosing.txtのバージョンが作業ディレクトリのバージョンと同じであるためです。

インデックスファイルは、新しいコミットのステージングエリアであることに加えて、ブランチをチェックアウトするときにオブジェクトデータベースからも設定され、マージ操作に関係するツリーを保持するために使用されます。詳細については、gitcore-tutorial[7] と関連するmanページを参照してください。

次にすること

この時点で、Gitコマンドのマニュアルページを読むために必要な知識はすべて習得しているはずです。まず、giteveryday[7]に記載されているコマンドから始めることをお勧めします。不明な専門用語はgitglossary[7]で見つけることができます。

Gitユーザーマニュアルでは、Gitについてより包括的な紹介をしています。

gitcvs-migration[7]では、CVSリポジトリをGitにインポートする方法と、CVSと同様の方法でGitを使用する方法について説明しています。

Gitの使用例については、ハウツーを参照してください。

Git開発者向けに、gitcore-tutorial[7]では、例えば新しいコミットの作成など、Gitの低レベルメカニズムについて詳細に説明しています。

GIT

git[1]スイートの一部

scroll-to-top