-
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デーモン
- 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 プラミングとポーセリン
- 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 プラミングコマンド
A2.2 付録B: アプリケーションへのGitの組み込み - Libgit2
Libgit2
利用可能なもう1つのオプションは、Libgit2を使用することです。 Libgit2は、他のプログラム内での使用に適した優れたAPIを持つことに重点を置いた、Gitの依存関係のない実装です。 https://libgit2.orgで確認できます。
まず、C APIがどのようなものかを見てみましょう。 簡単なツアーです。
// Open a repository
git_repository *repo;
int error = git_repository_open(&repo, "/path/to/repository");
// Dereference HEAD to a commit
git_object *head_commit;
error = git_revparse_single(&head_commit, repo, "HEAD^{commit}");
git_commit *commit = (git_commit*)head_commit;
// Print some of the commit's properties
printf("%s", git_commit_message(commit));
const git_signature *author = git_commit_author(commit);
printf("%s <%s>\n", author->name, author->email);
const git_oid *tree_id = git_commit_tree_id(commit);
// Cleanup
git_commit_free(commit);
git_repository_free(repo);
最初の数行は、Gitリポジトリを開きます。 git_repository
型は、メモリ内のキャッシュを持つリポジトリへのハンドルを表します。 これは、リポジトリの作業ディレクトリまたは.git
フォルダへの正確なパスがわかっている場合の最も簡単な方法です。 検索オプションを含むgit_repository_open_ext
、リモートリポジトリのローカルクローンを作成するためのgit_clone
とそれらに関連するメソッド、および完全に新しいリポジトリを作成するためのgit_repository_init
もあります。
コードの2番目のチャンクは、rev-parse構文(詳細についてはブランチ参照を参照)を使用して、HEADが最終的に指すコミットを取得します。 返される型はgit_object
ポインタであり、リポジトリのGitオブジェクトデータベースに存在するものを表します。 git_object
は実際には、いくつかの異なる種類のオブジェクトの「親」型です。「子」型のそれぞれのメモリレイアウトはgit_object
と同じであるため、正しい型に安全にキャストできます。 この場合、git_object_type(commit)
はGIT_OBJ_COMMIT
を返すため、git_commit
ポインタに安全にキャストできます。
次のチャンクは、コミットのプロパティにアクセスする方法を示しています。 ここでの最後の行では、git_oid
型を使用しています。これはSHA-1ハッシュのLibgit2の表現です。
このサンプルから、いくつかのパターンが出現し始めました。
-
ポインタを宣言して、その参照をLibgit2呼び出しに渡すと、その呼び出しはおそらく整数のエラーコードを返します。
0
の値は成功を示します。それより小さい値はエラーです。 -
Libgit2がポインタを設定する場合、それを解放する責任はあなたにあります。
-
Libgit2が呼び出しから
const
ポインタを返す場合、それを解放する必要はありませんが、それが属するオブジェクトが解放されると無効になります。 -
C言語を書くのは少し苦痛です。
最後の文は、Libgit2を使用する際にC言語を書く可能性は非常に低いことを意味します。幸いなことに、特定の言語と環境からGitリポジトリをかなり簡単に操作できるようにする、多くの言語固有のバインディングが利用可能です。Libgit2のRubyバインディングであるRuggedを使用して記述された上記の例を見てみましょう。Ruggedはhttps://github.com/libgit2/ruggedにあります。
repo = Rugged::Repository.new('path/to/repository')
commit = repo.head.target
puts commit.message
puts "#{commit.author[:name]} <#{commit.author[:email]}>"
tree = commit.tree
ご覧のとおり、コードははるかにすっきりしています。まず、Ruggedは例外を使用します。ConfigError
やObjectError
のようなものを発生させて、エラー状態を通知することができます。次に、Rubyはガベージコレクションされるため、リソースの明示的な解放はありません。もう少し複雑な例を見てみましょう。ゼロからコミットを作成する例です。
blob_id = repo.write("Blob contents", :blob) # (1)
index = repo.index
index.read_tree(repo.head.target.tree)
index.add(:path => 'newfile.txt', :oid => blob_id) # (2)
sig = {
:email => "bob@example.com",
:name => "Bob User",
:time => Time.now,
}
commit_id = Rugged::Commit.create(repo,
:tree => index.write_tree(repo), # (3)
:author => sig,
:committer => sig, # (4)
:message => "Add newfile.txt", # (5)
:parents => repo.empty? ? [] : [ repo.head.target ].compact, # (6)
:update_ref => 'HEAD', # (7)
)
commit = repo.lookup(commit_id) # (8)
-
新しいファイルのコンテンツを含む新しいブロブを作成します。
-
インデックスにHEADコミットのツリーを設定し、パス
newfile.txt
に新しいファイルを追加します。 -
これにより、ODBに新しいツリーが作成され、新しいコミットに使用されます。
-
作者フィールドとコミッターフィールドの両方に同じ署名を使用します。
-
コミットメッセージ。
-
コミットを作成するときは、新しいコミットの親を指定する必要があります。これは、単一の親にHEADの先端を使用します。
-
Rugged(およびLibgit2)は、コミットを作成するときに参照をオプションで更新できます。
-
戻り値は新しいコミットオブジェクトのSHA-1ハッシュで、それを使用して
Commit
オブジェクトを取得できます。
Rubyのコードはきれいで簡潔ですが、Libgit2が重い処理を行っているため、このコードもかなり高速に実行されます。Rubyプログラマーでない場合は、「その他のバインディング」で他のバインディングについて触れています。
高度な機能
Libgit2には、コアGitの範囲外のいくつかの機能があります。1つの例はプラグイン性です。Libgit2を使用すると、いくつかの種類の操作に対してカスタムの「バックエンド」を提供できるため、標準のGitとは異なる方法でデータを格納できます。Libgit2では、構成、refストレージ、オブジェクトデータベースなどのカスタムバックエンドが可能です。
これがどのように機能するかを見てみましょう。以下のコードは、Libgit2チームが提供するバックエンドの例(https://github.com/libgit2/libgit2-backendsにあります)から借用したものです。オブジェクトデータベースのカスタムバックエンドをセットアップする方法は次のとおりです。
git_odb *odb;
int error = git_odb_new(&odb); // (1)
git_odb_backend *my_backend;
error = git_odb_backend_mine(&my_backend, /*…*/); // (2)
error = git_odb_add_backend(odb, my_backend, 1); // (3)
git_repository *repo;
error = git_repository_open(&repo, "some-path");
error = git_repository_set_odb(repo, odb); // (4)
エラーはキャプチャされますが、処理されないことに注意してください。あなたのコードが私たちよりも優れていることを願っています。
-
空のオブジェクトデータベース(ODB)「フロントエンド」を初期化します。これは、実際の作業を行う「バックエンド」のコンテナとして機能します。
-
カスタムODBバックエンドを初期化します。
-
バックエンドをフロントエンドに追加します。
-
リポジトリを開き、オブジェクトを検索するためにODBを使用するように設定します。
しかし、このgit_odb_backend_mine
とは何でしょうか?これは、独自のODB実装のコンストラクタであり、git_odb_backend
構造体を適切に埋める限り、そこで好きなことができます。これは可能性のある例です。
typedef struct {
git_odb_backend parent;
// Some other stuff
void *custom_context;
} my_backend_struct;
int git_odb_backend_mine(git_odb_backend **backend_out, /*…*/)
{
my_backend_struct *backend;
backend = calloc(1, sizeof (my_backend_struct));
backend->custom_context = …;
backend->parent.read = &my_backend__read;
backend->parent.read_prefix = &my_backend__read_prefix;
backend->parent.read_header = &my_backend__read_header;
// …
*backend_out = (git_odb_backend *) backend;
return GIT_SUCCESS;
}
ここで最も微妙な制約は、my_backend_struct
の最初のメンバーがgit_odb_backend
構造体でなければならないことです。これにより、メモリレイアウトがLibgit2コードが期待するものであることが保証されます。残りは任意です。この構造体は、必要に応じて大きくすることも小さくすることもできます。
初期化関数は、構造体のメモリを割り当て、カスタムコンテキストを設定してから、それがサポートするparent
構造体のメンバーを埋めます。呼び出しシグネチャの完全なセットについては、Libgit2ソースのinclude/git2/sys/odb_backend.h
ファイルを参照してください。あなたの特定のユースケースは、これらのうちどれをサポートするかを決定するのに役立ちます。
その他のバインディング
Libgit2には、多くの言語のバインディングがあります。ここでは、この記事の執筆時点でより完全なバインディングパッケージのいくつかを使用した小さな例を示します。C ++、Go、Node.js、Erlang、JVMを含む他の多くの言語向けのライブラリが存在しますが、すべてさまざまな成熟段階にあります。公式のバインディングコレクションは、https://github.com/libgit2のリポジトリを閲覧することで見つけることができます。私たちが書くコードは、最終的にHEADが指すコミットからのコミットメッセージを返します(git log -1
のようなものです)。
LibGit2Sharp
.NETまたはMonoアプリケーションを作成している場合、探しているのはLibGit2Sharp(https://github.com/libgit2/libgit2sharp)です。バインディングはC#で記述されており、生のLibgit2の呼び出しをネイティブな感じのCLR APIでラップするために細心の注意が払われています。ここに例のプログラムを示します。
new Repository(@"C:\path\to\repo").Head.Tip.Message;
デスクトップWindowsアプリケーションの場合、すぐに開始するのに役立つNuGetパッケージもあります。
objective-git
アプリケーションがAppleプラットフォームで実行されている場合、実装言語としてObjective-Cを使用している可能性が高くなります。Objective-Git(https://github.com/libgit2/objective-git)は、その環境でのLibgit2バインディングの名前です。例のプログラムは次のようになります。
GTRepository *repo =
[[GTRepository alloc] initWithURL:[NSURL fileURLWithPath: @"/path/to/repo"] error:NULL];
NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message];
Objective-gitはSwiftと完全に相互運用可能であるため、Objective-Cを置き去りにした場合でも心配する必要はありません。
pygit2
PythonでのLibgit2のバインディングはPygit2と呼ばれ、https://www.pygit2.orgにあります。例のプログラムは次のとおりです。
pygit2.Repository("/path/to/repo") # open repository
.head # get the current branch
.peel(pygit2.Commit) # walk down to the commit
.message # read the message
さらに読む
もちろん、Libgit2の機能の完全な解説は、この本の範囲外です。Libgit2自体に関する詳細情報が必要な場合は、https://libgit2.github.com/libgit2にAPIドキュメントがあり、https://libgit2.github.com/docsにガイドセットがあります。他のバインディングについては、バンドルされているREADMEとテストを確認してください。多くの場合、小さなチュートリアルや、さらに読むためのポインタがあります。