Git
英語 ▾ トピック ▾ 最新バージョン ▾ gitworkflows 最終更新日 2.35.0

名前

gitworkflows - Git で推奨されるワークフローの概要

概要

git *

説明

このドキュメントは、git.git 自体で使用されているワークフロー要素のいくつかを書き留め、その理由を説明しようとするものです。多くのアイデアは一般的に適用できますが、関係する人が少ない小規模なプロジェクトでは、完全なワークフローはめったに必要ありません。

クイックリファレンスとして一連の*ルール*を定式化していますが、本文ではそれぞれのルールについて動機付けを試みています。常に文字通りに受け取らないでください。行動の正当な理由を、このマニュアルページよりも高く評価する必要があります。

変更の分離

原則として、変更を小さな論理的なステップに分割し、それぞれをコミットするようにしてください。それらは一貫性があり、後続のコミットとは独立して動作し、テストスイートに合格する必要があります。これにより、レビュープロセスがはるかに容易になり、履歴は、たとえば git-blame[1]git-bisect[1] を使用した後の検査と分析に非常に役立ちます。

これを達成するために、最初から作業を小さなステップに分割するようにしてください。いくつかのコミットをまとめて squash する方が、1 つの大きなコミットをいくつかに分割するよりも常に簡単です。途中で小さすぎる、または不完全なステップを踏むことを恐れないでください。公開する前に、後で git rebase --interactive を使用してコミットを編集することができます。 git stash push --keep-index を使用すると、他のコミットされていない変更とは独立してテストスイートを実行できます。 git-stash[1] の EXAMPLES セクションを参照してください。

ブランチの管理

あるブランチの変更を別のブランチに含めるために使用できる主なツールは 2 つあります: git-merge[1]git-cherry-pick[1] です。

マージには多くの利点があるため、マージだけでできるだけ多くの問題を解決しようとします。 cherry-pick は今でも時折役立ちます。以下の「上方向へのマージ」の例を参照してください。

最も重要なことは、マージはブランチレベルで動作するのに対し、cherry-pick はコミットレベルで動作することです。これは、マージは 1 つ、10 個、または 1000 個のコミットからの変更を同じように簡単に引き継ぐことができることを意味し、それはワークフローが多数の貢献者 (および貢献) に対してはるかにうまくスケーリングすることを意味します。マージコミットは、すべての親からのすべての変更が désormais 含まれているという「約束」であるため、マージは理解しやすいです。

もちろんトレードオフがあります。マージには、より慎重なブランチ管理が必要です。以下のサブセクションでは、重要なポイントについて説明します。

卒業

特定の機能が実験段階から安定段階に移行すると、ソフトウェアの対応するブランチ間でも「卒業」します。 git.git は、次の*統合ブランチ*を使用します

  • *maint* は、次の「メンテナンスリリース」、つまり最後にリリースされた安定バージョンの更新に含まれるべきコミットを追跡します。

  • *master* は、次のリリースに含まれるべきコミットを追跡します。

  • *next* は、master の安定性をテストするためにテストされているトピックのテストブランチとして意図されています。

少し異なって使用される 4 番目の公式ブランチがあります

  • *seen* (メンテナーによって確認されたパッチ) は、まだ組み込む準備ができていないものの統合ブランチです (以下の「統合ブランチ」を参照)。

4 つのブランチはそれぞれ、通常は上記のブランチの直接の子孫です。

概念的には、機能は不安定なブランチ (通常は *next* または *seen*) に入り、十分に安定していると見なされると、次のリリースのために *master* に「卒業」します。

上方向へのマージ

ただし、上記で説明した「下方向への卒業」は、実際には下方向にマージすることによって行うことはできません。なぜなら、不安定なブランチの*すべて*の変更が安定したブランチにマージされるからです。そのため、以下のようにします

ルール: 上方向にマージする

修正は常に、それを必要とする最も古いサポートされているブランチにコミットします。次に (定期的に) 統合ブランチを互いに上方向にマージします。

これにより、非常に制御された修正の流れが得られます。たとえば、*master* に適用した修正が *maint* でも必要であることに気付いた場合は、git-cherry-pick[1] を使用して下方向に cherry-pick する必要があります。これは何度か発生しますが、非常に頻繁に行わない限り心配する必要はありません。

トピックブランチ

重要な機能を実装するには、複数のパッチが必要になり、その存続期間中に追加のバグ修正や改善が行われる場合があります。

統合ブランチにすべてを直接コミットすると、多くの問題が発生します。コミットの取り消しができないため、1 つずつ revert する必要があります。これは履歴を混乱させ、変更のグループの一部を revert するのを忘れた場合にさらにエラーが発生する可能性があります。並行して作業すると変更が混ざり合い、さらに混乱が生じます。

「トピックブランチ」を使用すると、これらの問題が解決します。名前は一目瞭然ですが、上記の「上方向にマージする」ルールに由来する注意点があります

ルール: トピックブランチ

すべてのトピック (機能、バグ修正など) のサイドブランチを作成します。最終的にマージしたい最も古い統合ブランチからフォークオフします。

多くのことが非常に自然に行えるようになります

  • 機能/バグ修正を統合ブランチに取り込むには、単にマージします。その間にトピックがさらに進化した場合は、再度マージします。(必ずしも最初に最も古い統合ブランチにマージする必要はありません。たとえば、最初にバグ修正を *next* にマージし、テスト時間を与え、安定していることがわかったら *maint* にマージできます。)

  • トピックの作業を続けるためにブランチ *other* から新しい機能が必要になった場合は、*other* を *topic* にマージします。(ただし、これを「習慣的に」行わないでください。以下を参照してください。)

  • 間違ったブランチからフォークオフし、「過去に」戻したい場合は、git-rebase[1] を使用します。

最後のポイントは他の 2 つと矛盾することに注意してください。他の場所にマージされたトピックは rebase するべきではありません。 git-rebase[1] の RECOVERING FROM UPSTREAM REBASE のセクションを参照してください。

「習慣的に」(本当の理由もなく定期的に) 統合ブランチをトピックにマージすること、ひいては定期的に上流のものを下流のものにマージすることは、好ましくありません。

ルール: 明確に定義されたポイントでのみ下流にマージする

正当な理由がない限り、下流にマージしないでください。上流の API の変更がブランチに影響を与える。ブランチが上流にきれいにマージされない。など

そうしないと、マージされたトピックに、突然、単一の (明確に分離された) 変更以上のものが含まれるようになります。結果として生じる多くの小さなマージは、履歴を大幅に乱雑にします。後でファイルの履歴を調査する人は、そのマージが開発中のトピックに影響を与えたかどうかを調べる必要があります。上流は、誤って「より安定した」ブランチにマージされる可能性さえあります。など。

使い捨ての統合

最後の段落に従った場合、 désormais 多くの小さなトピックブランチがあり、それらがどのように相互作用するのか疑問に思うことがあります。おそらく、それらをマージした結果はうまくいかないでしょうか?しかしその一方で、そのようなマージは簡単には元に戻せないため、どこにも「安定した」場所にマージしたくありません。

もちろん、解決策は、元に戻すことができるマージを作成することです。使い捨てのブランチにマージします。

ルール: 使い捨ての統合ブランチ

いくつかのトピックの相互作用をテストするには、それらを使い捨てのブランチにマージします。そのようなブランチに基づいて作業をしてはいけません!

このブランチがテスト直後に削除されることを (非常に) 明確にすれば、このブランチを公開することもできます。たとえば、テスターに作業する機会を与えたり、他の開発者に進行中の作業が互換性があるかどうかを確認する機会を与えたりするためです。 git.git にはこのような *seen* と呼ばれる公式の使い捨て統合ブランチがあります。

リリースのためのブランチ管理

上記で説明したマージアプローチを使用していると仮定すると、プロジェクトをリリースするときに、追加のブランチ管理作業を行う必要があります。

機能リリースは *master* ブランチから作成されます。これは *master* が次の機能リリースに含まれるべきコミットを追跡するためです。

*master* ブランチは *maint* のスーパーセットであることが想定されています。この条件が満たされない場合、*maint* には *master* に含まれていないコミットが含まれています。したがって、これらのコミットによって表される修正は、機能リリースには含まれません。

*master* が実際に *maint* のスーパーセットであることを確認するには、git log を使用します

レシピ: *master* が *maint* のスーパーセットであることを確認する

git log master..maint

このコマンドはコミットをリストアップしません。そうでない場合は、*master* をチェックアウトし、*maint* をマージします。

これで、機能リリースの作成に進むことができます。リリースバージョンを示すタグを *master* の先端に適用します

レシピ: リリースタグ付け

git tag -s -m "Git X.Y.Z" vX.Y.Z master

新しいタグをパブリック Git サーバーにプッシュする必要があります (以下の「分散ワークフロー」を参照)。これにより、タグがプロジェクトを追跡している他のユーザーが使用できるようになります。プッシュは、リリースターボールの構築やフォーマット済みドキュメントページの作成など、リリース関連の項目を実行するための post-update フックをトリガーすることもあります。

同様に、メンテナンスリリースの場合、*maint* はリリースされるコミットを追跡しています。したがって、上記のステップでは、*master* ではなく *maint* にタグを付けてプッシュします。

機能リリース後のメンテナンスブランチの管理

機能リリース後、メンテナンスブランチを管理する必要があります。

まず、最新のリリースより前に作成された機能リリースに対してメンテナンス修正をリリースし続ける場合は、以前のリリースのコミットを追跡するための別のブランチを作成する必要があります。

これを行うには、現在のメンテナンスブランチを、以前のリリースバージョン番号(例:maint-X.Y.(Z-1)、X.Y.Z は現在のリリース)で名前が付けられた別のブランチにコピーします。

レシピ:maint のコピー

git branch maint-X.Y.(Z-1) maint

maint ブランチは、現在のリリースのメンテナンス修正を追跡できるように、新しくリリースされたコードに fast-forward する必要があります。

レシピ:maint を新しいリリースに更新する
  • git checkout maint

  • git merge --ff-only master

fast-forward できないためマージに失敗した場合は、maint の一部の修正が機能リリースで見落とされた可能性があります。前のセクションで説明したようにブランチの内容が検証されていれば、これは発生しません。

機能リリース後の next と seen ブランチの管理

機能リリース後、統合ブランチ next は、必要に応じて巻き戻され、next 上に残っているトピックを使用して master の先端から再構築できます。

レシピ:next を巻き戻して再構築する
  • git switch -C next master

  • git merge ai/topic_in_next1

  • git merge ai/topic_in_next2

  • …​

これを行う利点は、next の履歴がクリーンになることです。たとえば、next にマージされた一部のトピックは、最初は有望に見えましたが、後に望ましくないまたは時期尚早であることが判明する場合があります。このような場合、トピックは next から revert されますが、かつてマージされて revert されたという事実は履歴に残ります。next を再作成することで、そのようなトピックの別の化身に再試行するためのクリーンな状態を提供し、機能リリースはそうするための歴史の良いポイントです。

これを行う場合は、next が巻き戻されて再構築されたことを示す公開アナウンスを行う必要があります。

seen に対しても同じ巻き戻しと再構築のプロセスを実行できます。上記で説明したように、seen は使い捨てブランチであるため、公開アナウンスは必要ありません。

分散ワークフロー

最後のセクションの後、トピックの管理方法を理解しているはずです。一般的に、プロジェクトに取り組んでいるのはあなただけではないため、作業を共有する必要があります。

大まかに言って、マージとパッチという2つの重要なワークフローがあります。重要な違いは、マージワークフローはマージを含む完全な履歴を伝播できるのに対し、パッチは伝播できないことです。両方のワークフローを並行して使用できます。git.git では、サブシステムのメンテナーのみがマージワークフローを使用し、他の全員はパッチを送信します。

メンテナーは、組み込み用に送信されるすべてのコミット/パッチが準拠する必要がある「Signed-off-by」要件などの制限を課す場合があります。詳細については、プロジェクトのドキュメントを参照してください。

マージワークフロー

マージワークフローは、アップストリームとダウンストリーム間でブランチをコピーすることによって機能します。アップストリームは、公式の履歴にコントリビューションをマージできます。ダウンストリームは、公式の履歴に基づいて作業を行います。

これには、主に3つのツールを使用できます。

  • git-push[1] は、ブランチをリモートリポジトリにコピーします。通常は、関係者全員が読み取ることができるリポジトリにコピーします。

  • git-fetch[1] は、リモートブランチをリポジトリにコピーします。

  • git-pull[1] は、フェッチとマージを一度に行います。

最後の点に注意してください。リモートブランチを実際にマージする場合を除き、git pull を使用しないでください。

変更を取り出すのは簡単です

レシピ:プッシュ/プル:ブランチ/トピックの公開

git push <remote> <branch> を実行し、全員にどこからフェッチできるかを伝えます。

メールなどの他の手段で人に伝える必要があります。(Git は、このタスクを簡素化するために、事前にフォーマットされたプルリクエストをアップストリームメンテナーに送信するための git-request-pull[1] を提供します。)

統合ブランチの最新のコピーを取得したいだけで、最新の状態に保ちたい場合は、それも簡単です。

レシピ:プッシュ/プル:最新の状態に保つ

git fetch <remote> または git remote update を使用して、最新の状態に保ちます。

次に、前述のように、安定したリモートからトピックブランチをフォークします。

あなたがメンテナーであり、他の人のトピックブランチを統合ブランチにマージしたい場合、彼らは通常、メールでそうするようにリクエストを送信します。そのようなリクエストは次のようになります。

Please pull from
    <URL> <branch>

その場合、git pull は、次のように、フェッチとマージを一度に行うことができます。

レシピ:プッシュ/プル:リモートトピックのマージ

git pull <URL> <branch>

場合によっては、メンテナーがダウンストリームから変更をプルしようとすると、マージの競合が発生することがあります。この場合、彼らはダウンストリームにマージを実行して競合を自分で解決するように依頼できます(おそらく彼らはそれらを解決する方法をよりよく知っているでしょう)。ダウンストリームがアップストリームからマージ*すべき*まれなケースの1つです。

パッチワークフロー

あなたがメールの形でアップストリームに変更を送信するコントリビューターである場合、通常どおりトピックブランチを使用する必要があります(上記を参照)。次に、git-format-patch[1] を使用して、対応するメールを生成します(手動でフォーマットするよりも強くお勧めします。メンテナーの作業が楽になるためです)。

レシピ:format-patch/am:ブランチ/トピックの公開
  • git format-patch -M upstream..topic を使用して、事前にフォーマットされたパッチファイルに変換します

  • git send-email --to=<recipient> <patches>

詳細な使用方法については、git-format-patch[1] および git-send-email[1] のマニュアルページを参照してください。

メンテナーから、パッチが現在のアップストリームに適用されなくなったと言われた場合は、トピックをリベースする必要があります(マージを format-patch できないため、マージを使用できません)。

レシピ:format-patch/am:トピックを最新の状態に保つ

git pull --rebase <URL> <branch>

その後、リベース中に競合を修正できます。おそらく、あなたはメール以外ではトピックを公開していないので、リベースしても問題ありません。

このようなパッチシリーズを受け取った場合(メンテナーとして、または送信されたメーリングリストの読者として)、メールをファイルに保存し、新しいトピックブランチを作成し、*git am* を使用してコミットをインポートします。

レシピ:format-patch/am:パッチのインポート

git am < patch

指摘する価値のある機能の1つは、競合が発生した場合に役立つ3方向マージです。git am -3 は、パッチに含まれるインデックス情報を使用してマージベースを特定します。他のオプションについては、git-am[1] を参照してください。

GIT

git[1] スイートの一部

scroll-to-top