Git
チャプター ▾ 第2版

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ファイルを読み込むように構築されています。これは、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方向マージを試みます。パッチがベースにしていると記述されているコミットがリポジトリにない場合、このオプションは機能しないため、デフォルトではオンになっていません。そのコミットがある場合(パッチが公開コミットに基づいている場合)、-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

後で、別の素晴らしい機能を含む別のブランチがメールで送信されてきた場合は、リモートの設定がすでに完了しているので、直接fetchcheckoutを実行できます。

これは、一貫して誰かと作業している場合に最も役立ちます。誰かが時々1つのパッチだけをコントリビュートする場合は、全員に独自のサーバーを実行させ、いくつかのパッチを取得するためにリモートを継続的に追加および削除することを要求するよりも、メールでそれを受け入れる方が時間がかからない場合があります。また、1つまたは2つのパッチのみをコントリビュートする人のために、数百のリモートを持ちたいとは思わないでしょう。ただし、スクリプトとホストサービスによってこれが簡単になる場合があります。それは主に、どのように開発し、コントリビューターがどのように開発するかに依存します。

このアプローチのもう1つの利点は、コミットの履歴も取得できることです。正当なマージの問題がある可能性はありますが、履歴のどこに彼らの作業が基づいているかを知っています。適切な3方向マージがデフォルトであり、-3を指定してパッチがアクセスできる公開コミットから生成されることを期待する必要はありません。

一貫して誰かと作業していないが、それでもこの方法でプルしたい場合は、git pullコマンドにリモートリポジトリのURLを指定できます。これは1回限りのプルを実行し、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に渡すことができることを覚えておいてください。これにより、各コミットに導入されたdiffが付加されます。

このトピックブランチを別のブランチとマージした場合に何が起こるかの完全なdiffを確認するには、正しい結果を得るために奇妙なトリックを使用する必要がある場合があります。これを実行しようとするかもしれません。

$ git diff master

このコマンドはdiffを提供しますが、誤解を招く可能性があります。トピックブランチを作成してからmasterブランチが進んだ場合、奇妙な結果になる可能性があります。これは、Gitが現在いるトピックブランチの最後のコミットのスナップショットと、masterブランチの最後のコミットのスナップショットを直接比較するためです。たとえば、masterブランチのファイルに1行を追加した場合、スナップショットを直接比較すると、トピックブランチはその行を削除しようとしているように見えます。

masterがトピックブランチの直接の祖先である場合、これは問題ではありません。ただし、2つの履歴が分岐している場合、diffはトピックブランチにすべての新しいものが追加され、masterブランチに固有のものがすべて削除されるように見えます。

実際に見たいのは、トピックブランチに追加された変更、つまり、このブランチをmasterとマージした場合に導入される作業です。これを行うには、Gitにトピックブランチの最後のコミットを、masterブランチとの最初の共通の祖先と比較させます。

技術的には、共通の祖先を明示的に見つけてから、その上でdiffを実行することでそれを行うことができます。

$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db

または、より簡潔に

$ git diff $(git merge-base contrib master)

ただし、どちらも特に便利ではないため、Gitは同じことを行うための別の省略形を提供しています。3ドット構文です。git diffコマンドのコンテキストでは、別のブランチの後に3つのピリオドを置くと、現在いるブランチの最後のコミットと、別のブランチとの共通の祖先の間のdiffを実行できます。

$ git diff master...contrib

このコマンドは、現在のトピックブランチがmasterとの共通の祖先以降に導入した作業のみを示します。これは非常に便利な構文ですので、覚えておいてください。

コントリビューションされた作業の統合

トピックブランチのすべての作業がよりメインラインブランチに統合する準備ができたら、問題はどのように行うかということです。さらに、プロジェクトを維持するためにどのような全体的なワークフローを使用したいですか?多くの選択肢があるため、そのいくつかを取り上げます。

マージワークフロー

1つの基本的なワークフローは、すべての作業をmasterブランチに直接マージすることです。このシナリオでは、基本的に安定したコードを含むmasterブランチがあります。完了したと思うトピックブランチでの作業や、他の誰かがコントリビュートし、検証した作業がある場合は、それをmasterブランチにマージし、マージしたばかりのトピックブランチを削除して、繰り返します。

たとえば、複数のトピックブランチを持つ履歴のように見えるruby_clientphp_clientという名前の2つのブランチで作業を行うリポジトリがあり、ruby_clientの後にphp_clientをマージすると、履歴はトピックブランチのマージ後のようになります。

History with several topic branches
図72. 複数のトピックブランチを持つ履歴
After a topic branch merge
図73. トピックブランチのマージ後

これはおそらく最も簡単なワークフローですが、導入するものについて非常に注意する必要がある大規模またはより安定したプロジェクトを扱っている場合は、問題になる可能性があります。

より重要なプロジェクトがある場合は、2段階のマージサイクルを使用することをお勧めします。このシナリオでは、masterdevelopの2つの長期実行ブランチがあり、masterは非常に安定したリリースがカットされた場合にのみ更新され、すべての新しいコードはdevelopブランチに統合されると判断します。これらの両方のブランチを定期的にパブリックリポジトリにプッシュします。マージする新しいトピックブランチがあるたび(トピックブランチのマージ前)、それをdevelopにマージします(トピックブランチのマージ後)。次に、リリースにタグを付けるときに、安定したdevelopブランチがある場所にmasterを早送りします(プロジェクトリリース後)。

Before a topic branch merge
図74. トピックブランチのマージ前
After a topic branch merge
図75. トピックブランチのマージ後
After a project release
図76. プロジェクトリリース後

このようにすることで、プロジェクトのリポジトリをクローンした人は、masterをチェックアウトして最新の安定版をビルドし、それを簡単に最新の状態に保つことができます。あるいは、より最先端のコンテンツであるdevelopをチェックアウトすることもできます。さらに、すべての作業がマージされるintegrateブランチを作成することで、この概念を拡張することもできます。そして、そのブランチ上のコードベースが安定し、テストに合格したら、それをdevelopブランチにマージします。それがしばらく安定していることが証明されたら、masterブランチを早送りします。

大規模マージワークフロー

Gitプロジェクトには、masternext、および新規作業用のseen(以前は「pu」 - proposed updates)と、メンテナンスバックポート用のmaintの4つの長期実行ブランチがあります。コントリビューターによって新しい作業が導入されると、それらは、(並行して投稿されたトピックブランチの複雑なシリーズの管理を参照)で説明した方法と同様に、メンテナーのリポジトリのトピックブランチに収集されます。この時点で、トピックは、安全で消費の準備ができているか、またはさらに作業が必要かを判断するために評価されます。安全な場合は、nextにマージされ、そのブランチがプッシュアップされるため、誰もが統合されたトピックを試すことができます。

Managing a complex series of parallel contributed topic branches
図77. 並行して投稿されたトピックブランチの複雑なシリーズの管理

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

Merging contributed topic branches into long-term integration branches
図78. 長期統合ブランチへの投稿されたトピックブランチのマージ

トピックブランチが最終的にmasterにマージされたら、リポジトリから削除されます。Gitプロジェクトには、メンテナンスリリースが必要な場合にバックポートされたパッチを提供するために、最後のリリースからフォークされたmaintブランチもあります。したがって、Gitリポジトリをクローンすると、開発のさまざまな段階でプロジェクトを評価するためにチェックアウトできる4つのブランチがあり、どれほど最先端にしたいか、またはどのように貢献したいかに応じています。また、メンテナーは新しい貢献を審査するのに役立つ構造化されたワークフローを持っています。Gitプロジェクトのワークフローは特殊化されています。これを明確に理解するには、Gitメンテナーガイドを確認できます。

リベースおよびチェリーピックワークフロー

他のメンテナーは、ほとんど線形の履歴を維持するために、コントリビュートされた作業をマージするのではなく、masterブランチの上にリベースまたはチェリーピックすることを好みます。トピックブランチに作業があり、それを統合したいと判断した場合は、そのブランチに移動し、リベースコマンドを実行して、現在のmaster(またはdevelopなど)ブランチの上に変更を再構築します。それがうまくいけば、masterブランチを早送りすることができ、線形のプロジェクト履歴になります。

導入された作業をあるブランチから別のブランチに移動するもう1つの方法は、チェリーピックすることです。Gitのチェリーピックは、単一のコミットのリベースのようなものです。コミットで導入されたパッチを取得し、現在いるブランチに再適用しようとします。これは、トピックブランチに多数のコミットがあり、そのうちの1つだけを統合したい場合、またはトピックブランチに1つのコミットしかなく、リベースを実行するよりもチェリーピックすることを好む場合に役立ちます。たとえば、次のようなプロジェクトがあるとします。

Example history before a cherry-pick
図79. チェリーピック前の履歴例

コミットe43a6masterブランチにプルしたい場合は、次を実行できます。

$ 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値を取得します。これで、履歴は次のようになります。

History after cherry-picking a commit on a topic branch
図80. トピックブランチでのコミットのチェリーピック後の履歴

これで、トピックブランチを削除し、プルしたくないコミットを削除できます。

Rerere

多くのマージとリベースを行っている場合、または長期にわたるトピックブランチを維持している場合、Gitには「rerere」と呼ばれる便利な機能があります。

Rerereは「reuse recorded resolution(記録された解決策の再利用)」の略で、手動によるコンフリクト解決をショートカットする方法です。rerereが有効になっている場合、Gitは成功したマージの前後のイメージのセットを保持し、以前に修正したのとまったく同じようなコンフリクトがあることに気付いた場合、それを気にせずに前回の修正を単に使用します。

この機能は、構成設定とコマンドの2つの部分で構成されています。構成設定はrerere.enabledであり、グローバル構成に含めるのに十分便利です。

$ git config --global rerere.enabled true

これで、コンフリクトを解決するマージを実行するたびに、将来必要になった場合に備えて、解決策がキャッシュに記録されます。

必要に応じて、git rerereコマンドを使用してrerereキャッシュとやり取りできます。単独で呼び出されると、Gitは解決策のデータベースをチェックし、現在のマージコンフリクトとの一致を見つけようとし、それらを解決しようとします(ただし、rerere.enabledtrueに設定されている場合は、これは自動的に行われます)。また、記録される内容を確認したり、キャッシュから特定の解決策を消去したり、キャッシュ全体をクリアしたりするためのサブコマンドもあります。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プロジェクトのメンテナーは、公開キーをリポジトリ内のblobとして含め、そのコンテンツを直接指すタグを追加することで、この問題を解決しました。これを行うには、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データベースに直接インポートできます。これにより、その内容で新しいblobがGitに書き込まれ、blobの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タグが全員と共有されます。タグを検証したい場合は、データベースから直接blobをプルしてGPGにインポートすることで、PGPキーを直接インポートできます。

$ git show maintainer-pgp-pub | gpg --import

それらのキーを使用して、署名付きのすべてのタグを検証できます。また、タグメッセージに指示を含める場合、git show <tag>を実行すると、エンドユーザーにタグ検証に関するより具体的な指示を与えることができます。

ビルド番号の生成

Gitには、「v123」のような単調に増加する番号や、各コミットに対応する同等の番号がないため、コミットに対応する人間が読める名前が必要な場合は、そのコミットに対してgit describeを実行できます。応答として、Gitは、そのコミットより前の最新のタグの名前、そのタグからのコミット数、最後に説明されているコミットの部分的なSHA-1値(「g」という文字がGitを意味するプレフィックス付き)で構成される文字列を生成します。

$ 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出力名は無効になりました。

リリースの準備

これで、ビルドをリリースしたいと考えています。最初にやりたいことの1つは、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ディレクトリの下にプロジェクトの最新のスナップショットを取得します。同様の方法でzipアーカイブを作成することもできますが、git archive--format=zipオプションを渡します。

$ git archive master --prefix='project/' --format=zip > `git describe master`.zip

これで、プロジェクトのリリース用の素敵なtarballとzipアーカイブが作成され、Webサイトにアップロードしたり、人にメールで送信したりできます。

Shortlog

プロジェクトで何が起こっているかを知りたい人のメーリングリストにメールを送信する時が来ました。前回のリリースまたはメール以降にプロジェクトに追加されたものの変更履歴をすばやく取得する良い方法は、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以降のすべてのコミットのクリーンな要約が作成され、作成者別にグループ化されます。

scroll-to-top