-
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コマンド
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形式でダウンロードした場合、git am
をそのmboxファイルに向けることができ、認識したすべてのパッチを適用し始めます。複数のメールを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
を指定して、パッチがアクセスできるパブリックコミットから生成されたことを期待する必要はありません。
常に同じ人と作業しているわけではないけれど、この方法で彼らからプルしたい場合は、git pull
コマンドにリモートリポジトリの URL を指定できます。これは一時的なプルを行い、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
ブランチには含まれていないすべてのコミットを確認すると役立つことが多いです。master
ブランチのコミットを除外するには、ブランチ名の前に--not
オプションを追加します。これは、以前使用した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
ブランチのファイルに1行追加した場合、スナップショットの直接比較では、トピックブランチがその行を削除するように見えてしまいます。
もし 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
との共通祖先から導入した作業のみを表示します。これは覚えておくべき非常に便利な構文です。
貢献された作業の統合
トピックブランチ内のすべての作業を、よりメインラインのブランチに統合する準備が整ったとき、問題はそれをどのように行うかです。さらに、プロジェクトを維持するために全体的なワークフローをどのように使用したいですか?いくつか選択肢があるので、いくつか紹介します。
マージワークフロー
基本的なワークフローの1つは、そのすべての作業を直接master
ブランチにマージすることです。このシナリオでは、基本的に安定したコードを含むmaster
ブランチがあります。トピックブランチで完了したと思われる作業、または他の誰かが貢献し、あなたが検証した作業がある場合、それをマスターブランチにマージし、マージしたばかりのトピックブランチを削除し、繰り返します。
たとえば、いくつかのトピックブランチを持つ履歴 のように ruby_client
と php_client
という2つのブランチに作業があるリポジトリがあり、ruby_client
をマージした後に php_client
をマージすると、履歴は トピックブランチのマージ後 のようになります。


これはおそらく最も単純なワークフローですが、より大規模な、またはより安定したプロジェクトを扱っていて、導入する内容について非常に慎重になりたい場合には問題となる可能性があります。
より重要なプロジェクトがある場合、二段階のマージサイクルを使用したいかもしれません。このシナリオでは、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
ディレクトリの下にプロジェクトの最新スナップショットが取得されます。git archive
に--format=zip
オプションを渡すことで、同様の方法でzipアーカイブを作成することもできます。
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
これで、ウェブサイトにアップロードしたり、人々にメールで送ったりできる、プロジェクトリリースの素晴らしい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
以降のすべてのコミットのクリーンな要約が著者別にグループ化されて表示され、リストにメールで送ることができます。