-
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の内側
-
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 配管コマンド
5.3 分散Git - プロジェクトのメンテナンス
プロジェクトのメンテナンス
プロジェクトに効果的に貢献する方法を知っていることに加えて、プロジェクトをメンテナンスする方法を知っている必要もあるでしょう。これには、format-patch
で生成されメールで送られてきたパッチを受け入れて適用することや、自分のプロジェクトにリモートとして追加したリポジトリのリモートブランチの変更を統合することが含まれます。あなたが正統なリポジトリをメンテナンスしているか、パッチの検証や承認を手伝っているかにかかわらず、他の貢献者にとって最も明確で、長期的にあなたが維持できる方法で作業を受け入れる方法を知る必要があります。
トピックブランチでの作業
新しい作業を統合することを検討している場合、通常は「トピックブランチ」で試すのが良いアイデアです。トピックブランチとは、その新しい作業を試すために特別に作成された一時的なブランチです。これにより、個別にパッチを微調整したり、うまくいかない場合は、後で戻る時間ができるまでそれをそのままにしておくことが容易になります。これから試す作業のテーマに基づいて、ruby_client
や同様に分かりやすい名前の簡単なブランチ名を作成すれば、しばらく作業を中断して後で戻ってきた場合でも、簡単に思い出せます。Gitプロジェクトのメンテナーは、これらのブランチにも名前空間を設定する傾向があります。たとえば、sc/ruby_client
のように、sc
は作業を貢献した人の略です。ご記憶の通り、master
ブランチをベースにブランチを作成するには、次のようにします。
$ git branch sc/ruby_client master
あるいは、すぐにそのブランチに切り替えたい場合は、checkout -b
オプションを使用できます。
$ git checkout -b sc/ruby_client master
これで、受け取った貢献された作業をこのトピックブランチに追加し、長期的なブランチにマージするかどうかを決定する準備が整いました。
メールからのパッチ適用
プロジェクトに統合する必要があるパッチをメールで受け取った場合、それを評価するために、トピックブランチでそのパッチを適用する必要があります。メールされたパッチを適用する方法は、git apply
とgit am
の2つあります。
apply
を使ったパッチ適用
パッチがgit diff
またはUnixのdiff
コマンドの派生(推奨されません; 次のセクションを参照)で生成されたものを受け取った場合、git apply
コマンドで適用できます。パッチを/tmp/patch-ruby-client.patch
に保存したと仮定すると、パッチは次のように適用できます。
$ git apply /tmp/patch-ruby-client.patch
これは作業ディレクトリのファイルを変更します。patch -p1
コマンドを実行してパッチを適用するのとほぼ同じですが、より厳格で、patchよりも曖昧なマッチングを受け入れません。また、git diff
形式で記述されていれば、ファイルの追加、削除、名前変更も処理しますが、patch
ではできません。最後に、git apply
は「すべて適用するか、すべて中止するか」のモデルであり、すべてが適用されるか、何も適用されないかのどちらかですが、patch
は部分的にパッチファイルを適用することができ、作業ディレクトリを奇妙な状態にしてしまう可能性があります。git apply
は全体的にpatch
よりもはるかに保守的です。コミットは自動的に作成されません。実行後、導入された変更を手動でステージングしてコミットする必要があります。
実際に適用する前に、パッチがクリーンに適用されるかどうかを確認するためにgit apply
を使用することもできます。パッチを使ってgit apply --check
を実行します。
$ git apply --check 0001-see-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
出力がない場合、パッチはきれいに適用されるはずです。このコマンドは、チェックが失敗した場合にゼロ以外のステータスで終了するため、スクリプトで利用することもできます。
am
を使ったパッチ適用
貢献者がGitユーザーで、format-patch
コマンドを使ってパッチを生成してくれた場合、パッチには作成者情報とコミットメッセージが含まれているため、あなたの作業は楽になります。可能であれば、貢献者にはdiff
の代わりにformat-patch
を使ってパッチを生成するように促しましょう。git apply
は、古いパッチなどに対してのみ使用すればよいでしょう。
format-patch
で生成されたパッチを適用するには、git am
(このコマンドは「メールボックスから一連のパッチを適用する」ために使用されるため、am
と名付けられています)を使用します。技術的には、git am
はmboxファイルを読み込むように構築されています。mboxファイルとは、1つ以上のメールメッセージを1つのテキストファイルに保存するための、シンプルでプレーンテキスト形式のものです。それは次のように見えます。
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] Add limit to log function
Limit log functionality to the first 20
これは、前のセクションで見たgit format-patch
コマンドの出力の始まりであり、有効なmboxメール形式も表しています。誰かがgit send-email
を使って適切にパッチをメールで送ってきて、それをmbox形式でダウンロードした場合、そのmboxファイルをgit am
に指定すれば、見つかったすべてのパッチを適用し始めます。複数のメールをmbox形式で保存できるメールクライアントを使用している場合、パッチシリーズ全体をファイルに保存し、その後git am
を使用してそれらを1つずつ適用できます。
ただし、誰かがgit format-patch
で生成されたパッチファイルをチケットシステムなどにアップロードした場合、そのファイルをローカルに保存し、そのディスクに保存されたファイルをgit am
に渡して適用することができます。
$ git am 0001-limit-log-function.patch
Applying: Add limit to log function
きれいに適用され、新しいコミットが自動的に作成されたことがわかります。作成者情報はメールのFrom
とDate
ヘッダーから取得され、コミットメッセージはメールのSubject
と本文(パッチの前)から取得されます。例えば、このパッチが上記のmboxの例から適用された場合、生成されたコミットは次のようになります。
$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author: Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit: Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700
Add limit to log function
Limit log functionality to the first 20
Commit
情報はパッチを適用した人物と適用時刻を示しています。Author
情報は、パッチを最初に作成した個人とその作成時刻です。
しかし、パッチがきれいに適用されないこともあります。おそらく、メインブランチがパッチの元になったブランチから大きく分岐しているか、パッチがまだ適用されていない別のパッチに依存しているかのどちらかでしょう。その場合、git am
プロセスは失敗し、何をしたいか尋ねてきます。
$ git am 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".
このコマンドは、競合するマージやリベース操作と非常に似ており、問題のあるファイルに競合マーカーを配置します。この問題の解決方法は非常に似ています。ファイルを編集して競合を解決し、新しいファイルをステージングし、その後git am --resolved
を実行して次のパッチに進みます。
$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: See if this helps the gem
Gitに競合をもう少し賢く解決させたい場合は、-3
オプションを渡すことができます。これにより、Gitは3-wayマージを試みます。このオプションはデフォルトではオンになっていません。なぜなら、パッチが基づいているとされているコミットがリポジトリにない場合、機能しないからです。そのコミットを持っている場合、つまりパッチがパブリックなコミットに基づいていた場合、-3
オプションは競合するパッチの適用に関して通常はるかに賢明です。
$ git am -3 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
この場合、-3
オプションがなければパッチは競合と見なされていただろう。-3
オプションが使われたため、パッチはきれいに適用された。
mboxから多数のパッチを適用している場合、am
コマンドをインタラクティブモードで実行することもできます。これは、見つけた各パッチで停止し、適用するかどうかを尋ねます。
$ git am -3 -i mbox
Commit Body is:
--------------------------
See if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
これにより、多数のパッチを保存している場合に便利です。そのパッチが何だったか覚えていない場合はまずパッチを表示できますし、すでに適用済みの場合は適用しないという選択もできます。
トピックのすべてのパッチがブランチに適用されコミットされたら、それらを長期実行ブランチに統合するかどうか、どのように統合するかを選択できます。
リモートブランチをチェックアウトする
貢献が、自身のリポジトリを設定し、多数の変更をプッシュした後、そのリポジトリのURLと変更が含まれているリモートブランチ名をあなたに送ってきたGitユーザーからのものであった場合、彼らをリモートとして追加し、ローカルでマージを行うことができます。
たとえば、ジェシカが彼女のリポジトリのruby-client
ブランチに素晴らしい新機能があるというメールを送ってきた場合、リモートを追加してそのブランチをローカルでチェックアウトすることでテストできます。
$ git remote add jessica https://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
彼女が後日、別の素晴らしい機能を含む別のブランチで再びメールを送ってきた場合、すでにリモートが設定されているため、直接fetch
してcheckout
することができます。
これは、一貫して協力している人と作業する場合に最も役立ちます。誰かがたまにしかパッチを1つだけ貢献しない場合、メールで受け入れる方が、全員に自分のサーバーを実行させ、少数のパッチを取得するために継続的にリモートを追加および削除するよりも時間がかからないかもしれません。また、パッチを1つか2つしか貢献しない人ごとに何百ものリモートを持つことはあまり望ましくないでしょう。ただし、スクリプトやホスト型サービスによってこれが容易になる場合もあります。これは主に、あなたの開発方法と貢献者の開発方法に依存します。
このアプローチのもう一つの利点は、コミットの履歴も得られることです。正当なマージ問題が発生する可能性はありますが、彼らの作業があなたの履歴のどこに基づいているかを知っています。適切な3者間マージがデフォルトとなり、-3
を指定して、パッチがアクセス可能なパブリックコミットから生成されたことを期待する必要はありません。
一貫して特定の人物と作業しているわけではないが、それでもこの方法で彼らからプルしたい場合は、リモートリポジトリのURLをgit pull
コマンドに提供できます。これは一度限りのプルを行い、URLをリモート参照として保存しません。
$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
* branch HEAD -> FETCH_HEAD
Merge made by the 'recursive' strategy.
導入される内容の特定
これで、貢献された作業を含むトピックブランチができました。この時点で、それらをどうするか決めることができます。このセクションでは、いくつかのコマンドを再確認し、これらをどのように使用して、この作業をメインブランチにマージした場合に正確に何が導入されるかを確認できるかを見ていきます。
このブランチに含まれているが、master
ブランチには含まれていないすべてのコミットをレビューすることは、しばしば役立ちます。ブランチ名の前に--not
オプションを追加することで、master
ブランチのコミットを除外できます。これは、以前使用したmaster..contrib
形式と同じことを行います。たとえば、貢献者が2つのパッチを送ってきて、あなたがcontrib
というブランチを作成し、そこにそれらのパッチを適用した場合、次のように実行できます。
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Oct 24 09:53:59 2008 -0700
See if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date: Mon Oct 22 19:38:36 2008 -0700
Update gemspec to hopefully work better
各コミットがどのような変更を導入するかを確認するには、-p
オプションをgit log
に渡すと、各コミットに導入された差分が追加されることを思い出してください。
このトピックブランチを別のブランチとマージした場合に何が起こるか、その完全な差分を見るには、正しい結果を得るために奇妙なトリックを使用する必要があるかもしれません。次のように実行しようと考えるかもしれません。
$ git diff master
このコマンドは差分を表示しますが、誤解を招く可能性があります。トピックブランチを作成してからmaster
ブランチが進んだ場合、一見奇妙な結果が得られます。これは、Gitが、現在いるトピックブランチの最後のコミットのスナップショットと、master
ブランチの最後のコミットのスナップショットを直接比較するためです。たとえば、master
ブランチのファイルに行を追加した場合、スナップショットの直接比較では、トピックブランチがその行を削除するように見えます。
master
がトピックブランチの直接の祖先である場合、これは問題になりません。しかし、2つの履歴が分岐している場合、差分はトピックブランチの新しいものをすべて追加し、master
ブランチに固有のものをすべて削除するように見えます。
本当に見たいのは、トピックブランチに追加された変更、つまりこのブランチをmaster
とマージした場合に導入される作業です。それを行うには、Gitにトピックブランチの最後のコミットと、master
ブランチとの最初の共通祖先を比較させます。
技術的には、共通祖先を明示的に特定し、それに対して差分を実行することでこれを行うことができます。
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
または、より簡潔に
$ git diff $(git merge-base contrib master)
ただし、どちらも特に便利ではないため、Gitは同じことを行う別の省略記法としてトリプルドット構文を提供しています。git diff
コマンドのコンテキストでは、別のブランチの後に3つのピリオドを置くと、現在のブランチの最後のコミットとそのブランチの共通祖先との間のdiff
を実行できます。
$ git diff master...contrib
このコマンドは、現在のトピックブランチがmaster
との共通祖先以降に導入した作業のみを表示します。これは覚えておくと非常に便利な構文です。
貢献された作業の統合
トピックブランチのすべての作業がよりメインのブランチに統合される準備ができたとき、問題となるのはその方法です。さらに、プロジェクトを維持するためにどのような全体的なワークフローを使用したいですか?いくつかの選択肢があるので、そのうちのいくつかを説明します。
マージワークフロー
基本的なワークフローの一つは、すべての作業を単純にmaster
ブランチに直接マージすることです。このシナリオでは、基本的に安定したコードを含むmaster
ブランチがあります。完了したと思われるトピックブランチの作業、または他の誰かが貢献し、あなたが検証した作業がある場合、それをマスターブランチにマージし、マージしたばかりのトピックブランチを削除し、繰り返します。
たとえば、複数のトピックブランチを持つ履歴のように、ruby_client
とphp_client
という2つのブランチに作業があるリポジトリがあり、ruby_client
、次にphp_client
をマージすると、履歴はトピックブランチのマージ後のようになります。


それはおそらく最も単純なワークフローですが、より大規模または安定したプロジェクトを扱っていて、何を導入するかについて非常に注意したい場合には、問題になる可能性があります。
より重要なプロジェクトがある場合は、2段階のマージサイクルを使用したいかもしれません。このシナリオでは、master
とdevelop
という2つの長期実行ブランチがあり、master
は非常に安定したリリースがカットされた場合にのみ更新され、すべての新しいコードはdevelop
ブランチに統合されると判断します。あなたはこれらの両方のブランチを定期的に公開リポジトリにプッシュします。新しいトピックブランチをマージするたびに(トピックブランチのマージ前)、それをdevelop
にマージし(トピックブランチのマージ後)、その後、リリースにタグを付ける際に、安定したdevelop
ブランチがある場所までmaster
をファストフォワードします(プロジェクトリリース後)。



これにより、人々があなたのプロジェクトのリポジトリをクローンする際、master
をチェックアウトして最新の安定版をビルドし、それを簡単に最新の状態に保つこともできますし、develop
をチェックアウトしてより最先端のコンテンツを利用することもできます。また、すべての作業を統合するintegrate
ブランチを持つことで、この概念を拡張することもできます。そして、そのブランチのコードベースが安定し、テストに合格したら、それをdevelop
ブランチにマージし、それがしばらく安定していることが証明されたら、master
ブランチをファストフォワードします。
大規模なマージワークフロー
Gitプロジェクトには、新しい作業のためのmaster
、next
、seen
(以前は「pu」 — 提案された更新)、そしてメンテナンスのバックポートのためのmaint
という4つの長期実行ブランチがあります。貢献者によって新しい作業が導入されると、メンテナーのリポジトリで、これまで説明したのと同様の方法でトピックブランチに集められます(並行して貢献された複雑な一連のトピックブランチの管理を参照)。この時点で、トピックは安全で消費可能かどうか、あるいはさらなる作業が必要かどうかを判断するために評価されます。安全であれば、next
にマージされ、そのブランチはプッシュアップされて、誰もが統合されたトピックを試せるようになります。

まだ作業が必要なトピックは、代わりにseen
にマージされます。完全に安定したと判断されると、トピックはmaster
に再マージされます。その後、next
とseen
ブランチはmaster
から再構築されます。これは、master
がほぼ常に前進し、next
は時々リベースされ、seen
はさらに頻繁にリベースされることを意味します。

トピックブランチが最終的にmaster
にマージされると、リポジトリから削除されます。Gitプロジェクトには、メンテナンスリリースが必要な場合に備えて、最後のリリースからフォークされたバックポートパッチを提供するmaint
ブランチもあります。したがって、Gitリポジトリをクローンすると、開発の異なる段階でプロジェクトを評価するためにチェックアウトできる4つのブランチがあります。これは、あなたがどれだけ最先端を追求したいか、またはどのように貢献したいかによって異なります。また、メンテナーは新しい貢献を精査するための構造化されたワークフローを持っています。Gitプロジェクトのワークフローは特殊です。これを明確に理解するには、Gitメンテナーズガイドを確認するとよいでしょう。
リベースとチェリーピックのワークフロー
他のメンテナーは、ほとんど線形な履歴を保つために、貢献された作業をmaster
ブランチにマージするのではなく、その上にリベースまたはチェリーピックすることを好みます。トピックブランチに作業があり、それを統合したいと判断したら、そのブランチに移動し、リベースコマンドを実行して、現在のmaster
(またはdevelop
など)ブランチの上に変更を再構築します。それがうまく機能すれば、master
ブランチをファストフォワードでき、線形なプロジェクト履歴が得られます。
導入された作業をあるブランチから別のブランチへ移動させるもう一つの方法は、チェリーピックです。Gitでのチェリーピックは、単一のコミットに対するリベースのようなものです。コミットで導入されたパッチを取り出し、現在いるブランチに再適用しようとします。これは、トピックブランチに複数のコミットがあり、そのうちの1つだけを統合したい場合、またはトピックブランチに1つのコミットしかなく、リベースを実行するよりもチェリーピックしたい場合に役立ちます。例えば、次のようなプロジェクトがあるとします。

コミットe43a6
をmaster
ブランチにプルしたい場合、次のように実行できます。
$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)
これはe43a6
で導入されたものと同じ変更をプルしますが、適用日が異なるため、新しいコミットSHA-1値を取得します。これで履歴は次のようになります。

これで、トピックブランチを削除し、取り込みたくなかったコミットを破棄できます。
Rerere
たくさんのマージやリベースを行う場合、あるいは長期間存続するトピックブランチを管理している場合、Gitには「rerere」と呼ばれる便利な機能があります。
Rerereは「reuse recorded resolution」(記録された解決の再利用)の略で、手動での競合解決をショートカットする手段です。rerereが有効になっている場合、Gitは成功したマージからの前後のイメージのセットを保持し、以前に解決したものと全く同じ競合に気づくと、前回からの解決策をそのまま使用し、あなたに煩わせることはありません。
この機能は、設定とコマンドの2つの部分から構成されます。設定はrerere.enabled
で、グローバル設定に入れておくと非常に便利です。
$ git config --global rerere.enabled true
これで、競合を解決するマージを行うたびに、将来必要になった場合に備えて、解決策がキャッシュに記録されます。
必要であれば、git rerere
コマンドを使用してrerereキャッシュとやり取りできます。単独で呼び出された場合、Gitはその解決策のデータベースをチェックし、現在のマージ競合と一致するものを見つけて解決しようとします(ただし、rerere.enabled
がtrue
に設定されている場合、これは自動的に行われます)。また、何を記録するかを確認したり、特定の解決策をキャッシュから消去したり、キャッシュ全体をクリアしたりするためのサブコマンドもあります。rerereについては、Rerereでさらに詳しく説明します。
リリースのタグ付け
リリースをカットすることを決定したら、将来どの時点でもそのリリースを再作成できるように、タグを割り当てたいと思うでしょう。Gitの基本で説明したように、新しいタグを作成できます。あなたがメンテナーとしてタグに署名することにした場合、タグ付けは次のようになるでしょう。
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
タグに署名する場合、タグの署名に使用した公開PGPキーを配布する問題が発生する可能性があります。Gitプロジェクトのメンテナーは、公開キーをリポジトリにブロブとして含め、そのコンテンツを直接指すタグを追加することでこの問題を解決しました。これを行うには、gpg --list-keys
を実行して、どのキーが必要かを確認します。
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid Scott Chacon <schacon@gmail.com>
sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
次に、キーをエクスポートし、それをgit hash-object
にパイプすることで、Gitデータベースに直接インポートできます。これにより、そのコンテンツを持つ新しいブロブがGitに書き込まれ、そのブロブのSHA-1値が返されます。
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
これでキーのコンテンツがGitに入ったので、hash-object
コマンドが提供した新しいSHA-1値を指定して、それを直接指すタグを作成できます。
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
git push --tags
を実行すると、maintainer-pgp-pub
タグは全員と共有されます。誰かがタグを検証したい場合、データベースから直接ブロブをプルし、それをGPGにインポートすることで、あなたのPGPキーを直接インポートできます。
$ git show maintainer-pgp-pub | gpg --import
彼らはその鍵を使ってあなたの署名されたすべてのタグを検証できます。また、タグメッセージに指示を含めておけば、git show <tag>
を実行することで、エンドユーザーにタグ検証に関するより具体的な指示を与えることができます。
ビルド番号の生成
Gitには、各コミットに付随する「v123」のような単調に増加する番号やそれと同等のものがないため、コミットに人間が読める名前を付けたい場合は、そのコミットに対してgit describe
を実行できます。その応答として、Gitは、そのコミットよりも前の最新のタグの名前、そのタグ以降のコミット数、そして最後に記述されるコミットの部分的なSHA-1値(Gitを意味する「g」の文字がプレフィックスとして付く)からなる文字列を生成します。
$ git describe master
v1.6.2-rc1-20-g8c5b85c
このようにして、スナップショットをエクスポートしたりビルドしたりして、人々が理解できる名前を付けることができます。実際、GitリポジトリからクローンされたソースコードからGitをビルドすると、git --version
はこのようなものを表示します。もし直接タグ付けしたコミットを記述している場合は、単にタグ名を表示します。
デフォルトでは、git describe
コマンドは注釈付きタグ(-a
または-s
フラグで作成されたタグ)を必要とします。軽量(非注釈付き)タグも利用したい場合は、コマンドに--tags
オプションを追加します。この文字列はgit checkout
またはgit show
コマンドのターゲットとしても使用できますが、末尾の短縮されたSHA-1値に依存しているため、永久に有効であるとは限りません。例えば、Linuxカーネルは最近、SHA-1オブジェクトの一意性を確保するために、8文字から10文字にジャンプしたため、古いgit describe
の出力名は無効になりました。
リリースの準備
さあ、ビルドをリリースしましょう。Gitを使わないかわいそうな人たちのために、コードの最新のスナップショットをアーカイブにしたいと思うでしょう。これを行うコマンドはgit archive
です。
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
誰かがそのtarballを開くと、project
ディレクトリの下にプロジェクトの最新のスナップショットが得られます。同様に、--format=zip
オプションをgit archive
に渡すことで、zipアーカイブを作成することもできます。
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
これで、Webサイトにアップロードしたり、人々にメールで送ったりできる、プロジェクトリリースの素晴らしいtarballとzipアーカイブが手に入りました。
ショートログ
プロジェクトで何が起こっているか知りたい人々のメーリングリストにメールを送る時が来ました。前回のリリースやメール以降にプロジェクトに追加されたものの変更履歴を素早く得る良い方法は、git shortlog
コマンドを使用することです。これは、指定した範囲内のすべてのコミットを要約します。たとえば、前回のリリースがv1.0.1
だった場合、以下のコマンドは前回のリリース以降のすべてのコミットの要約を提供します。
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (6):
Add support for annotated tags to Grit::Tag
Add packed-refs annotated tag support.
Add Grit::Commit#to_patch
Update version and History.txt
Remove stray `puts`
Make ls_tree ignore nils
Tom Preston-Werner (4):
fix dates in history
dynamic version method
Version bump to 1.0.2
Regenerated gemspec for version 1.0.2
v1.0.1
以降のすべてのコミットが作成者ごとにグループ化された簡潔な要約が得られ、それをリストにメールで送信できます。