-
1. はじめに
- 1.1 バージョン管理について
- 1.2 Gitの簡単な歴史
- 1.3 Gitとは?
- 1.4 コマンドライン
- 1.5 Gitのインストール
- 1.6 初めてのGit設定
- 1.7 ヘルプの利用
- 1.8 まとめ
-
2. Gitの基本
- 2.1 Gitリポジトリの取得
- 2.2 リポジトリへの変更の記録
- 2.3 コミット履歴の表示
- 2.4 変更の取り消し
- 2.5 リモートリポジトリの操作
- 2.6 タグ付け
- 2.7 Gitエイリアス
- 2.8 まとめ
-
3. Gitブランチ
- 3.1 ブランチの概要
- 3.2 基本的なブランチ操作とマージ
- 3.3 ブランチ管理
- 3.4 ブランチワークフロー
- 3.5 リモートブランチ
- 3.6 リベース
- 3.7 まとめ
-
4. サーバー上のGit
- 4.1 プロトコル
- 4.2 サーバーへのGitの導入
- 4.3 SSH公開鍵の生成
- 4.4 サーバーのセットアップ
- 4.5 Git Daemon
- 4.6 スマートHTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 サードパーティのホスティングオプション
- 4.10 まとめ
-
5. 分散Git
- 5.1 分散ワークフロー
- 5.2 プロジェクトへの貢献
- 5.3 プロジェクトの管理
- 5.4 まとめ
-
6. GitHub
- 6.1 アカウントのセットアップと構成
- 6.2 プロジェクトへの貢献
- 6.3 プロジェクトの管理
- 6.4 組織の管理
- 6.5 GitHubのスクリプト化
- 6.6 まとめ
-
7. Gitツール
- 7.1 リビジョン選択
- 7.2 インタラクティブステージング
- 7.3 スタッシュとクリーニング
- 7.4 作業への署名
- 7.5 検索
- 7.6 履歴の書き換え
- 7.7 resetの解説
- 7.8 高度なマージ
- 7.9 Rerere
- 7.10 Gitを使ったデバッグ
- 7.11 サブモジュール
- 7.12 バンドル
- 7.13 置換
- 7.14 認証情報の保存
- 7.15 まとめ
-
8. Gitのカスタマイズ
- 8.1 Gitの設定
- 8.2 Git属性
- 8.3 Gitフック
- 8.4 Git強制ポリシーの例
- 8.5 まとめ
-
9. Gitと他のシステム
- 9.1 クライアントとしてのGit
- 9.2 Gitへの移行
- 9.3 まとめ
-
10. Gitの内部構造
- 10.1 配管(Plumbing)と磁器(Porcelain)
- 10.2 Gitオブジェクト
- 10.3 Gitの参照
- 10.4 パックファイル
- 10.5 リフスペック
- 10.6 転送プロトコル
- 10.7 メンテナンスとデータ復旧
- 10.8 環境変数
- 10.9 まとめ
-
A1. 付録A:その他の環境でのGit
- A1.1 グラフィカルインターフェース
- A1.2 Visual StudioでのGit
- A1.3 Visual Studio CodeでのGit
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMineでのGit
- A1.5 Sublime TextでのGit
- A1.6 BashでのGit
- A1.7 ZshでのGit
- A1.8 PowerShellでのGit
- A1.9 まとめ
-
A2. 付録B:アプリケーションへのGitの組み込み
- A2.1 コマンドラインGit
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. 付録C:Gitコマンド
- A3.1 セットアップと構成
- A3.2 プロジェクトの取得と作成
- A3.3 基本的なスナップショット
- A3.4 ブランチとマージ
- A3.5 プロジェクトの共有と更新
- A3.6 検査と比較
- A3.7 デバッグ
- A3.8 パッチ
- A3.9 メール
- A3.10 外部システム
- A3.11 管理
- A3.12 配管コマンド
10.3 Gitの内部構造 - Gitの参照
Gitの参照
たとえば、コミット1a410e
から到達可能なリポジトリの履歴を見たい場合、git log 1a410e
のようなコマンドを実行してその履歴を表示できます。しかし、1a410e
がその履歴の開始点として使用したいコミットであることを覚えておく必要があります。代わりに、SHA-1値を単純な名前で保存できるファイルがあれば、生のSHA-1値の代わりにその単純な名前を使用できるため、より簡単になります。
Gitでは、これらの単純な名前は「参照」または「ref」と呼ばれます。これらのSHA-1値を含むファイルは、.git/refs
ディレクトリにあります。現在のプロジェクトでは、このディレクトリにはファイルは含まれていませんが、単純な構造が含まれています。
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
最新のコミットがどこにあるかを覚えるのに役立つ新しい参照を作成するには、技術的には次のように簡単な操作を実行できます
$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master
これで、GitコマンドでSHA-1値の代わりに作成したばかりのhead参照を使用できます
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
参照ファイルを直接編集することは推奨されていません。代わりに、Gitは、参照を更新したい場合に、より安全なコマンドgit update-ref
を提供します
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
これが基本的にGitのブランチです。作業ラインのヘッドへの単純なポインタまたは参照です。2番目のコミットに戻るブランチを作成するには、次のようにします
$ git update-ref refs/heads/test cac0ca
ブランチには、そのコミットからの作業のみが含まれます
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
これで、Gitデータベースは概念的には次のようになります

git branch <ブランチ>
のようなコマンドを実行すると、Gitは基本的にそのupdate-ref
コマンドを実行して、現在いるブランチの最後のコミットのSHA-1を作成したい新しい参照に追加します。
HEAD
ここで問題となるのは、git branch <ブランチ>
を実行したときに、Gitが最後のコミットのSHA-1をどのように知るかということです。その答えはHEADファイルです。
通常、HEADファイルは現在いるブランチへのシンボリック参照です。シンボリック参照とは、通常の参照とは異なり、別の参照へのポインタが含まれていることを意味します。
ただし、まれに、HEADファイルにGitオブジェクトのSHA-1値が含まれる場合があります。これは、タグ、コミット、またはリモートブランチをチェックアウトしたときに発生し、リポジトリは「デタッチされたHEAD」状態になります。
ファイルを見ると、通常は次のようになります
$ cat .git/HEAD
ref: refs/heads/master
git checkout test
を実行すると、Gitはファイルを次のように更新します
$ cat .git/HEAD
ref: refs/heads/test
git commit
を実行すると、コミットオブジェクトが作成され、そのコミットオブジェクトの親はHEADの参照が指すSHA-1値になります。
このファイルを手動で編集することもできますが、ここでも同様に、より安全なコマンドgit symbolic-ref
が存在します。このコマンドを使用してHEADの値を読み取ることができます
$ git symbolic-ref HEAD
refs/heads/master
同じコマンドを使用してHEADの値を設定することもできます
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
refsスタイル以外のシンボリック参照を設定することはできません
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
タグ
Gitの3つの主要なオブジェクトタイプ(*blob*、*tree*、*commit*)について説明を終えましたが、4番目のタイプがあります。 *tag*オブジェクトはコミットオブジェクトと非常によく似ています。タグ付け者、日付、メッセージ、およびポインタが含まれています。主な違いは、タグオブジェクトが通常、ツリーではなくコミットを指していることです。ブランチ参照のようなものですが、移動することはありません。常に同じコミットを指しますが、よりわかりやすい名前が付けられます。
Gitの基本で説明したように、タグには注釈付きと軽量の2種類があります。軽量タグは、次のようなコマンドで作成できます。
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
軽量タグは、移動しない参照にすぎません。一方、注釈付きタグはより複雑です。注釈付きタグを作成すると、Gitはタグオブジェクトを作成し、コミットに直接ではなく、そのオブジェクトを指す参照を書き込みます。注釈付きタグ(-a
オプションを使用)を作成することで、これを確認できます。
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'Test tag'
これが作成されたオブジェクトのSHA-1値です。
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
次に、そのSHA-1値に対してgit cat-file -p
を実行します。
$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
Test tag
オブジェクトのエントリが、タグ付けしたコミットのSHA-1値を指していることに注目してください。また、コミットを指す必要はなく、任意のGitオブジェクトをタグ付けできることにも注目してください。たとえば、Gitのソースコードでは、メンテナーがGPG公開鍵をblobオブジェクトとして追加し、それをタグ付けしています。Gitリポジトリのクローンでこれを実行すると、公開鍵を表示できます。
$ git cat-file blob junio-gpg-pub
Linuxカーネルリポジトリにも、コミットを指さないタグオブジェクトがあります。最初に作成されたタグは、ソースコードのインポートの最初のツリーを指しています。
リモート
3番目の種類の参照は、リモート参照です。リモートを追加してプッシュすると、Gitはrefs/remotes
ディレクトリ内の各ブランチについて、最後にそのリモートにプッシュした値を保存します。たとえば、origin
というリモートを追加し、master
ブランチをそこにプッシュできます。
$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
a11bef0..ca82a6d master -> master
すると、refs/remotes/origin/master
ファイルを確認することで、サーバーと最後に通信したときのorigin
リモート上のmaster
ブランチがどうだったかを確認できます。
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
リモート参照は、ブランチ(refs/heads
参照)と主に、読み取り専用と見なされる点で異なります。git checkout
でチェックアウトできますが、GitはHEADをそれに対してシンボリックに参照しないため、commit
コマンドで更新することはありません。Gitは、それらのブランチがそれらのサーバーにあった最後の既知の状態へのブックマークとしてそれらを管理します。