-
1. Gitを始めるにあたって
- 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 PlumbingとPorcelain
- 10.2 Gitオブジェクト
- 10.3 Gitリファレンス
- 10.4 Packfile
- 10.5 Refspec
- 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 Plumbingコマンド
A2.3 付録B: アプリケーションにGitを埋め込む - JGit
JGit
Javaプログラム内からGitを使いたい場合、JGitと呼ばれるフル機能のGitライブラリがあります。JGitはJavaでネイティブに書かれた比較的にフル機能のGit実装であり、Javaコミュニティで広く使われています。JGitプロジェクトはEclipseの傘下にあり、その本拠地はhttps://www.eclipse.org/jgit/にあります。
セットアップ
JGitとプロジェクトを接続し、コードを書き始める方法はいくつかあります。おそらく最も簡単なのはMavenを使うことです。統合は、pom.xml
ファイルの<dependencies>
タグに以下のスニペットを追加することで実現されます。
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.5.0.201409260305-r</version>
</dependency>
このドキュメントを読んでいる頃には、version
は進んでいる可能性が高いです。最新のリポジトリ情報はhttps://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgitで確認してください。このステップが完了すると、Mavenは必要なJGitライブラリを自動的に取得して使用します。
バイナリ依存関係を自分で管理したい場合は、事前にビルドされたJGitバイナリがhttps://www.eclipse.org/jgit/downloadから入手できます。次のようなコマンドを実行してプロジェクトにビルドすることができます。
javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App
配管 (Plumbing)
JGitには、配管(Plumbing)と磁器(Porcelain)の2つの基本的なAPIレベルがあります。これらの用語はGit自体に由来しており、JGitもほぼ同じ種類の領域に分かれています。磁器APIは、一般的なユーザーレベルのアクション(通常のユーザーがGitコマンドラインツールを使うようなもの)のための使いやすいフロントエンドであり、配管APIは、低レベルのリポジトリオブジェクトと直接対話するためのものです。
ほとんどのJGitセッションの開始点はRepository
クラスであり、最初にインスタンスを作成する必要があります。ファイルシステムベースのリポジトリ(はい、JGitは他のストレージモデルも許可しています)の場合、これはFileRepositoryBuilder
を使って実現されます。
// Create a new repository
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();
// Open an existing repository
Repository existingRepo = new FileRepositoryBuilder()
.setGitDir(new File("my_repo/.git"))
.build();
ビルダーは、プログラムが正確な場所を知っているかどうかに関わらず、Gitリポジトリを見つけるために必要なすべてのものを提供する流暢なAPIを持っています。環境変数を使用したり(.readEnvironment()
)、作業ディレクトリ内の場所から検索を開始したり(.setWorkTree(…).findGitDir()
)、あるいは上記のように既知の.git
ディレクトリを開いたりすることができます。
Repository
インスタンスがあれば、さまざまな操作を行うことができます。いくつか例を挙げましょう。
// Get a reference
Ref master = repo.getRef("master");
// Get the object the reference points to
ObjectId masterTip = master.getObjectId();
// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");
// Load raw object contents
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);
// Create a branch
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();
// Delete a branch
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();
// Config
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");
ここではたくさんのことが起こっているので、一つずつ見ていきましょう。
最初の行は、master
リファレンスへのポインタを取得します。JGitは、refs/heads/master
にある実際のmaster
リファレンスを自動的に取得し、そのリファレンスに関する情報を取得できるオブジェクトを返します。名前 (.getName()
) を取得したり、ダイレクトリファレンスのターゲットオブジェクト (.getObjectId()
) やシンボリックリファレンスが指すリファレンス (.getTarget()
) を取得したりできます。Refオブジェクトはタグのリファレンスやオブジェクトを表すためにも使用されるため、タグが「剥がされている(peeled)」かどうか、つまりタグオブジェクトの(潜在的に長い)文字列の最終ターゲットを指しているかどうかを尋ねることができます。
2行目はmaster
リファレンスのターゲットを取得し、ObjectIdインスタンスとして返されます。ObjectIdはオブジェクトのSHA-1ハッシュを表し、Gitのオブジェクトデータベースに存在する場合としない場合があります。3行目も同様ですが、JGitがrev-parse構文をどのように処理するかを示しています(これについてはブランチリファレンスを参照してください)。Gitが理解する任意のオブジェクト指定子を渡すことができ、JGitはそのオブジェクトの有効なObjectIdまたはnull
を返します。
次の2行は、オブジェクトの生のコンテンツをロードする方法を示しています。この例では、ObjectLoader.copyTo()
を呼び出してオブジェクトのコンテンツを直接標準出力にストリーミングしていますが、ObjectLoaderにはオブジェクトのタイプとサイズを読み取るメソッドや、バイト配列として返すメソッドもあります。大きなオブジェクト(.isLarge()
がtrue
を返す場合)の場合、.openStream()
を呼び出して、生のオブジェクトデータをすべて一度にメモリに読み込むことなく読み取れるInputStreamのようなオブジェクトを取得できます。
次の数行は、新しいブランチを作成するために必要なものを示しています。RefUpdateインスタンスを作成し、いくつかのパラメータを設定し、.update()
を呼び出して変更をトリガーします。これに続いて、同じブランチを削除するコードがあります。これには.setForceUpdate(true)
が必要であることに注意してください。そうしないと、.delete()
呼び出しはREJECTED
を返し、何も起こりません。
最後の例は、Git設定ファイルからuser.name
の値を取得する方法を示しています。このConfigインスタンスは、以前に開いたリポジトリをローカル設定に使用しますが、グローバルおよびシステム設定ファイルを自動的に検出し、そこからも値を読み取ります。
これはフル機能の配管APIのほんの一部にすぎません。他にも多くのメソッドやクラスが利用可能です。また、JGitがエラーを処理する方法、つまり例外を使用する方法はここでは示されていません。JGit APIは、標準的なJava例外(IOException
など)をスローすることがありますが、JGit固有の例外タイプも多数提供されています(NoRemoteRepositoryException
、CorruptObjectException
、NoMergeBaseException
など)。
磁器 (Porcelain)
配管APIは非常に完全ですが、インデックスにファイルを追加したり、新しいコミットを作成したりするような一般的な目標を達成するためにそれらを連結するのは煩雑になる可能性があります。JGitは、これを助けるためのより高レベルなAPIセットを提供しており、これらのAPIへのエントリーポイントはGit
クラスです。
Repository repo;
// construct repo...
Git git = new Git(repo);
Gitクラスには、かなり複雑な動作を構築するために使用できる、優れた高レベルのビルダースタイルのメソッドセットがあります。git ls-remote
のような例を見てみましょう。
CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd");
Collection<Ref> remoteRefs = git.lsRemote()
.setCredentialsProvider(cp)
.setRemote("origin")
.setTags(true)
.setHeads(false)
.call();
for (Ref ref : remoteRefs) {
System.out.println(ref.getName() + " -> " + ref.getObjectId().name());
}
これはGitクラスの一般的なパターンです。メソッドはコマンドオブジェクトを返し、それによってパラメータを設定するためのメソッド呼び出しをチェーンさせることができ、これらは.call()
を呼び出すと実行されます。このケースでは、origin
リモートにタグを要求していますが、ヘッドは要求していません。また、認証にCredentialsProvider
オブジェクトを使用していることにも注目してください。
他にも多くのコマンドがGitクラスを通じて利用可能で、add
、blame
、commit
、clean
、push
、rebase
、revert
、reset
などが含まれますが、これらに限定されません。
さらに読む
これはJGitの全機能のほんの一部です。興味があり、さらに詳しく知りたい場合は、情報やインスピレーションを探す場所を以下に示します。
-
JGitの公式APIドキュメントはhttps://www.eclipse.org/jgit/documentationで入手できます。これらは標準のJavadocなので、お気に入りのJVM IDEでもローカルにインストールできます。
-
https://github.com/centic9/jgit-cookbookのJGitクックブックには、JGitで特定のタスクを実行する方法の多くの例が記載されています。