Articles

A successful Git branching model

Posted on

反省点(2020年3月5日)

このモデルは2010年に考案されたもので、今から10年以上前、Git自体が誕生してからそれほど時間が経っていません。

この10年の間に、Git自体が世界を席巻し、Gitを使って開発されている最も人気のあるソフトウェアのタイプは、少なくとも私のフィルターバブルの中では、Webアプリにシフトしています。

これは、10年前にこのブログを書いたときに私が思い描いていたソフトウェアの種類ではありません。

もしあなたのチームがソフトウェアの継続的なデリバリーを行っているのであれば、git-flowをチームに組み込むのではなく、もっとシンプルなワークフロー(GitHubflowなど)を採用することをお勧めします。

しかし、明示的にバージョン管理されたソフトウェアを作っている場合や、ソフトウェアの複数のバージョンを野生でサポートする必要がある場合には、git-flowは過去10年間の人々と同様にあなたのチームに適しているかもしれません。

最後に、万能薬は存在しないことを常に念頭に置いてください。 自分の置かれている状況を考えてみてください。 憎しみは禁物です。

この投稿では、私が約 1 年前にいくつかのプロジェクト (仕事とプライベートの両方) に導入し、非常に成功した開発モデルを紹介します。 これまでずっと書こうと思っていたのですが、なかなか時間が取れず、今になってしまいました。

なぜ git なのか?

中央集権的なソースコード管理システムと比較した場合の Git の長所と短所については、theweb を参照してください。 そこではたくさんの炎上騒ぎが起きています。 開発者として、私は今日の他のツールよりもGitを気に入っています。

しかし、Gitでは、これらのアクションは非常に安価でシンプルであり、毎日のワークフローの中核部分の一つと考えられています。

例えば、CVS/Subversionの本では、分岐やマージは後の章(上級者向け)で初めて取り上げられますが、Gitの本では、第3章(基本)ですでに取り上げられています。

そのシンプルさと反復的な性質の結果として、分岐やマージはもはや怖いものではありません。

ツールの話はここまでにして、次は開発モデルの話をしましょう。

ツールの話はこれくらいにして、開発モデルに向かいましょう。ここで紹介するモデルは、基本的には、管理されたソフトウェア開発プロセスに到達するために、すべてのチーム メンバーが従わなければならない一連の手順にすぎません。

Decentralized but centralized ¶

私たちが使用しているリポジトリ セットアップで、このブランチ モデルとうまく機能しているのは、中央の「真実」レポがあるものです。 このレポは中央のものとしか考えられていないことに注意してください (Git は DVCS なので、技術的なレベルでは中央のレポというものは存在しません)。

各開発者は、オリジンに対してプルとプッシュを行います。 しかし、中央でのプッシュ・プルの関係に加えて、各開発者は他のピアから変更をプルして、サブチームを形成することもできます。 例えば、大きな新機能を2人以上の開発者で共同で開発した後に、進行中の作業をoriginに早急にプッシュする場合などに有効です。

技術的には、アリスがボブのリポジトリを指す bob という名前の Git リモートを定義し、その逆を行うということ以上の意味はありません。

主要なブランチ¶

中核となる開発モデルは、既存のモデルに大きく影響されています。 セントラル リポには、無限のライフタイムを持つ 2 つのメイン ブランチがあります。

  • master
  • develop

masterorigin は、Git ユーザーなら誰でも知っているはずです。

masterdevelopという別のブランチが存在します。

origin/masterHEADのソースコードは常に生産可能な状態を反映しています。

origin/developHEADのソース コードが、次のリリースのために届けられた最新の開発変更が常に反映されている状態のメイン ブランチだと考えています。 これを「統合ブランチ」と呼ぶ人もいます。

developmaster にマージして、リリース番号を付ける必要があります。

従って、変更が mastermasterへのコミットがあるたびに、Git フック スクリプトを使用してソフトウェアを自動的にビルドし、本番サーバーにロールアウトすることができますが、私たちはこれを非常に厳格に行う傾向があります。

サポートブランチ ¶

メインブランチ masterdevelop の次に、私たちの開発モデルでは、チームメンバー間の並行開発を助け、機能の追跡を容易にし、本番リリースの準備をし、本番での問題を迅速に修正するために、さまざまなサポートブランチを使用しています。 メインブランチとは異なり、これらのブランチは、最終的に削除されるため、常に限られた時間しか持ちません。

使用するブランチの種類は次のとおりです。

  • Featureブランチ
  • Releaseブランチ
  • Hotfixブランチ

これらのブランチにはそれぞれ特定の目的があり、どのブランチを元のブランチにするか、どのブランチをマージターゲットにするかといった厳格なルールに縛られています。

これらのブランチは、技術的な観点からは決して「特別」なものではありません。 ブランチの種類は、私たちがどのように使用するかによって分類されます。

Feature branches ¶

May branch off from:developMust merge back into:developmasterdeveloprelease-*hotfix-*

機能ブランチ(トピックブランチと呼ばれることもあります)は、今後のリリースに向けて新しい機能を開発するために使用されます。 ある機能の開発を始めるとき、その機能がどのリリースに組み込まれるかは、その時点ではわからないかもしれません。 機能ブランチの本質は、機能が開発されている間は存在しますが、最終的には develop にマージされるか (新機能を次期リリースに確実に追加するため)、または破棄されます (期待外れの実験の場合)。

機能ブランチは通常、開発者リポジトリにのみ存在し、originには存在しません。

機能ブランチの作成 ¶

新機能の作業を開始するときは、developブランチから分岐します。

$ git checkout -b myfeature developSwitched to a new branch "myfeature"

完成した機能をdevelopに取り込む ¶

完成した機能をdevelopブランチにマージして、次期リリースに確実に追加することができます。

$ git checkout developSwitched to branch 'develop'$ git merge --no-ff myfeatureUpdating ea1b82a..05e9557(Summary of changes)$ git branch -d myfeatureDeleted branch myfeature (was 05e9557).$ git push origin develop

--no-ff フラグを使用すると、マージが「早送り」で実行された場合でも、常に新しいコミット オブジェクトが作成されます。 これにより、機能ブランチの歴史的な存在についての情報が失われるのを防ぎ、機能を追加したすべてのコミットをまとめます。 比較:

後者の場合、どのコミット オブジェクトが一緒に機能を実装したかを Git の履歴から確認することはできません – すべてのログ メッセージを手動で読む必要があります。 機能全体 (つまりコミットのグループ) の取り消しは、後者の状況では本当に頭痛の種になりますが、--no-ff フラグが使用されていれば、簡単に行うことができます。

確かに、いくつかの (空の) コミット オブジェクトが作成されますが、コストよりもはるかに大きな利益が得られます。

リリース ブランチ¶

May branch off from:developMust merge back into:developmasterrelease-*

リリースブランチは、新しいプロダクションリリースの準備をサポートします。 リリースブランチは、新しいプロダクションリリースの準備をサポートしています。これにより、直前になっても i の点と t の点を埋めることができます。 さらに、ちょっとしたバグフィックスや、リリースのメタデータ (バージョン番号、ビルドデートなど) の作成も可能です。

developdevelopdevelopブランチは「次のリリース」のための変更を反映していましたが、その「次のリリース」が最終的に 0.3 になるのか 1.0 になるのかは、リリース ブランチが開始されるまでは不明です。

リリースブランチの作成¶

リリースブランチは developdevelopの状態は「次のリリース」の準備ができており、これを(1.1.6や2.0ではなく)バージョン1.2にすることを決定しました。

$ git checkout -b release-1.2 developSwitched to a new branch "release-1.2"$ ./bump-version.sh 1.2Files modified successfully, version bumped to 1.2.$ git commit -a -m "Bumped version number to 1.2" Bumped version number to 1.21 files changed, 1 insertions(+), 1 deletions(-)

新しいブランチを作成してそこに切り替えた後、バージョン番号を変更します。ここで、bump-version.shは、作業コピー内のいくつかのファイルを変更して新しいバージョンを反映させる架空のシェルスクリプトです。 もちろん、手動での変更も可能です。

この新しいブランチは、リリースが確実にロールアウトされるまで、しばらくの間存在するかもしれません。

この新しいブランチは、リリースが確実にロールアウトされるまで、しばらくの間存在します。その間、バグフィックスは (developブランチではなく) このブランチで適用されるかもしれません。 大きな新機能をこのブランチに追加することは厳しく禁じられています。

developにマージする必要があるため、次の大きなリリースを待つことになります。

リリースブランチの完成¶

リリースブランチの状態が実際のリリースになる準備ができたら、いくつかのアクションを実行する必要があります。 まず、リリース ブランチはmastermastermaster上のコミットは、この歴史的なバージョンを将来参照しやすいようにタグ付けされなければなりません。

Git の最初の 2 つのステップ:

$ git checkout masterSwitched to branch 'master'$ git merge --no-ff release-1.2Merge made by recursive.(Summary of changes)$ git tag -a 1.2

これでリリースは完了し、将来の参照のためにタグ付けされました。

編集: -s-u <key> フラグを使用して、タグを暗号化して署名するのもいいかもしれません。

リリースブランチで行われた変更を維持するためには、それらをdevelopにマージする必要があります。 Gitでは、

$ git checkout developSwitched to branch 'develop'$ git merge --no-ff release-1.2Merge made by recursive.(Summary of changes)

このステップは、マージの衝突につながる可能性があります (バージョン番号を変更しているので、おそらく衝突しないでしょう)。 その場合は、修正してコミットしてください。

これで完了です。リリースブランチはもう必要ないので、削除しても構いません。

$ git branch -d release-1.2Deleted branch release-1.2 (was ff452fe).

Hotfix branches ¶

May branch off from:masterMust merge back into:developmasterhotfix-*

Hotfixブランチは、予定外ではありますが、新しいプロダクションリリースの準備をするという点で、リリースブランチとよく似ています。 ホットフィックスブランチは、本番バージョンに望ましくない状態が発生したときに、すぐに対処する必要があることから生まれます。 製品版の重大なバグをすぐに解決しなければならない場合、製品版を示す master ブランチの対応するタグから hotfix ブランチを分岐させることができます。

要は、チームメンバー(developブランチ上)の作業を続けながら、別の人が本番用の迅速な修正を準備できるということです。

Hotfixブランチの作成 ¶

Hotfixブランチはmasterdevelopの変更はまだ不安定です。

$ git checkout -b hotfix-1.2.1 masterSwitched to a new branch "hotfix-1.2.1"$ ./bump-version.sh 1.2.1Files modified successfully, version bumped to 1.2.1.$ git commit -a -m "Bumped version number to 1.2.1" Bumped version number to 1.2.11 files changed, 1 insertions(+), 1 deletions(-)

ブランチオフした後、バージョン番号を上げるのを忘れないでください!

そして、バグを修正し、1つまたは複数の別のコミットで修正をコミットします。

$ git commit -m "Fixed severe production problem" Fixed severe production problem5 files changed, 32 insertions(+), 17 deletions(-)

Hotfixブランチの終了¶

終了したら、バグフィックスをmastermasterdevelopにもマージする必要があります。

まず、masterを更新し、リリースをタグ付けします。

$ git checkout masterSwitched to branch 'master'$ git merge --no-ff hotfix-1.2.1Merge made by recursive.(Summary of changes)$ git tag -a 1.2.1

編集: -s-u <key> フラグを使用して、タグを暗号化したいと思うかもしれません。

次に、developにもバグフィックスを入れます。

$ git checkout developSwitched to branch 'develop'$ git merge --no-ff hotfix-1.2.1Merge made by recursive.(Summary of changes)

例外として、現在リリースブランチが存在する場合は、ホットフィックスの変更をdevelopdevelopdevelopdevelopにマージすることができます。)

最後に、一時的なブランチを削除します。

$ git branch -d hotfix-1.2.1Deleted branch hotfix-1.2.1 (was abbe5d6).

まとめ¶

このブランチ モデルには、本当に衝撃的な新しいものは何もありませんが、この記事で始めた「大局的な」図は、私たちのプロジェクトで非常に役立つことがわかりました。 この図は、理解しやすいエレガントなメンタル モデルを形成し、チーム メンバーが分岐とリリースのプロセスについて共通の理解を深めることができます。

更新: ご要望にお応えして、メインの図の画像 (Apple Keynote) の thegitflow-model.src.key を掲載しました。


Git-branching-model.pdf

このブログの他の記事

  • 日常的に使えるGitパワーツール
  • デコーダー入門
  • 技術的負債は本当の負債
  • 美しいコード
  • 美しい地図

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です