#6 ブランチ命名規則を技術的に強制する - Python OSS開発記録
python 14 min read

#6 ブランチ命名規則を技術的に強制する - Python OSS開発記録

avatar-m-1

karrinn

著者

Git Flowでブランチ戦略を決めても、実際には命名規則がバラバラになりがち。
「あれ、このブランチどのルールで作ったんだっけ?」を技術的に防ぐ方法を実装します。

KEY TAKEAWAYS

この記事でわかること

  • GitHub Rulesetsの "creation" ルールで命名パターンに合わないブランチ作成をブロック
  • exclude条件で「許可するパターン」を定義(include: ~ALL + exclude: 許可パターン)
  • コミュニケーションコスト削減: 命名ルール違反を指摘する手間が消える

用語の定義

TERM 01

Branch Naming Convention

ブランチ命名規則。Git Flowでは feature/fix/ などのプレフィックスでブランチの種類を識別する。

TERM 02

Ref Name Conditions

GitHub Rulesetsで使う条件指定。include(対象)と exclude(除外)でブランチ名パターンを制御。

TERM 03

Creation Rule

Rulesetsで「ブランチ作成」を制限するルール。条件に合わないブランチの作成を技術的にブロック。

TERM 04

~ALL

GitHub Rulesetsの特殊パターン。「すべてのブランチ」を意味する。include: ["~ALL"] + exclude で「これ以外禁止」を実現。

なぜ「人の注意」に頼ってはいけないのか

wagtail-reusable-blocks では、 Topic #4で決めたGit Flowのブランチ戦略(feature/*fix/*hotfix/*chore/*docs/*)を強制する仕組みを入れました。

理由は単純。人間は忘れるし、間違える

よくある問題1

feature/add-block ← OK
add-block ← プレフィックスなし

よくある問題2

new-feature ← 適当な名前
test ← 論外

結果

ブランチ一覧を見ても
何のブランチか分からない

解決策: GitHub Rulesetsの "creation" ルール技術的にブロック。「CONTRIBUTING.mdに書いてあるから守ってね」ではなく、ルール違反のブランチは作れないようにする。

特にOSSでは、初めて参加する人がいきなりルールを完璧に守るのは難しい。GitHubで「そのブランチ名は作れません」と返せば、それで終わり。

「branch-naming」Rulesetの実装

命名規則違反をpushすると...

問題: 命名規則がバラバラになる

Git Flowを導入しても、実際には命名規則が守られないことがよくあります。

「ブランチ名、どうすればいいんだっけ?」と毎回CONTRIBUTINGを読み返すのは面倒だし、レビュー時に「ブランチ名がルールと違いますよ」とコメントするのもお互いに消耗します。

解決策: 技術的に制限する

GitHub Rulesetsの "creation" ルールを使えば、条件に合わないブランチは作成できないようにできます。

Topic #5で設定した「default」Rulesetはブランチ保護(削除禁止、force push禁止など)。
今回の「branch-naming」Rulesetはブランチ作成の制限です。

bash
$ git checkout -b test-branch
Switched to a new branch 'test-branch'

$ git push -u origin test-branch
remote: error: GH013: Repository rule violations found for refs/heads/test-branch.
remote:
remote: - RULE: branch-naming
remote:   Creation of this ref is not allowed. Only branches matching these patterns are allowed:
remote:     - refs/heads/main
remote:     - refs/heads/develop
remote:     - refs/heads/feature/*
remote:     - refs/heads/fix/*
remote:     - refs/heads/hotfix/*
remote:     - refs/heads/release/*
remote:     - refs/heads/chore/*
remote:     - refs/heads/docs/*
remote:
To github.com:kkm-horikawa/wagtail-reusable-blocks.git
! [remote rejected] test-branch -> test-branch (push declined due to repository rule violations)
error: failed to push some refs

test-branch という名前のブランチは作成できません。
許可されているパターン(feature/* など)に合わせる必要があります。

「branch-naming」Rulesetの全容

設定内容の詳細

wagtail-reusable-blocksの「branch-naming」Rulesetは、非常にシンプルです。

基本設定

  • Target: Branch(ブランチ作成を対象)
  • Enforcement: Active(有効)
  • Rules: Creation(ブランチ作成ルール)
  • Conditions: Ref Name(ブランチ名の条件)

Ref Name Conditionsの設定

include: ["~ALL"]

すべてのブランチを対象にする

exclude: [許可するパターン]

以下のパターンを除外 = 許可する。

  • refs/heads/main
  • refs/heads/develop
  • refs/heads/feature/*
  • refs/heads/fix/*
  • refs/heads/hotfix/*
  • refs/heads/release/*
  • refs/heads/chore/*
  • refs/heads/docs/*

「~ALL + exclude」の意味:include: ["~ALL"] で「すべてのブランチ」を対象にし、 exclude で「これは例外(許可)」を指定。
つまり、excludeに入っていないパターンはすべてブロックされる。

json
{
"id": 10492190,
"name": "branch-naming",
"target": "branch",
"enforcement": "active",
"rules": [
{
"type": "creation"
}
],
"conditions": {
"ref_name": {
"include": ["~ALL"],
"exclude": [
"refs/heads/main",
"refs/heads/develop",
"refs/heads/feature/*",
"refs/heads/fix/*",
"refs/heads/hotfix/*",
"refs/heads/release/*",
"refs/heads/chore/*",
"refs/heads/docs/*"
]
}
},
"bypass_actors": []
}

bypass_actors について:
空配列 [] = 誰もバイパスできない
Admin権限を持っていても、このルールは例外なく適用されます。

GitHub UIでの設定手順

ステップバイステップ

Step 1: Rulesetsページを開く

  1. リポジトリ → Settings
  2. 左サイドバー → Rules → Rulesets
  3. 「New ruleset」→「New branch ruleset」

Step 2: 基本情報を入力

入力項目:

  • Ruleset Name:branch-naming
  • Enforcement status: Active
  • Bypass list: 空(誰もバイパスできない)

Bypass listについて:
Admin権限を持つ人でもルールをバイパスできなくします。緊急時は一時的にRulesetを無効化する方が安全。

Step 3: ターゲットブランチを指定

Target branches:

  • 「Add target」→ 「Include by pattern」
  • Pattern: ~ALL
  • 「Add target」→ 「Exclude by pattern」
  • Patterns: main, develop, feature/**, fix/**, hotfix/**, release/**, chore/**, docs/**

UIとAPIのパターン表記の違い:
UI: feature/**feature/ 配下すべて)
API: refs/heads/feature/*(ref形式で表記)
意味は同じです。UIの方が簡潔。

Step 4: ルールを選択

チェックする項目:

Step 5: 保存

「Create」ボタンを押して完了。

確認方法: 命名規則に合わないブランチをpushしてみる → エラーが出ればOK

OSS vs 企業プロジェクト: ブランチ命名規則の強制

OSS: 初めての人が迷わないために

OSSプロジェクトでは、初めてPRを送る人がたくさんいます。
その人たちに「ブランチ名はこのルールで」と伝えても、忘れることもあるし、間違えることもある

技術的に制限すれば、間違えようがない
「このブランチ名は使えません」とGitHubが教えてくれるので、レビュー時に指摘する手間も消える

メリット

  • コントリビューター側: ルールを完璧に覚えなくても大丈夫(間違えたらGitHubが教えてくれる)
  • メンテナー側: 「ブランチ名が違いますよ」と指摘する手間がゼロ
  • プロジェクト全体: ブランチ一覧が整理され、「何のブランチか」が一目で分かる

優しさの技術的実装: 「ルールを守ってね」と伝えるだけでは人間の記憶力に依存している。
技術的に制限することで、誰もが迷わず参加できる環境を作る。

企業: 「不安」から「安心」へ

Topic #4, #5で触れた「萎縮による開発効率の激減」問題は、ブランチ命名規則でも同じです。

新入社員や異動者が「どういうブランチ名で作ればいいの?」と質問するのは、不安だからです。
「間違えたら怒られる」「システムを壊すかもしれない」という恐怖が、質問を生みます。

従来の問題: 脅しと萎縮

  • 「命名規則を守れ!間違えるな!」 ← 脅し
  • 新人は萎縮: 「これで合ってるのかな?」と不安になる
  • 質問の嵐: 毎回確認しないと怖い
  • 教える側も消耗: 同じ説明を何度も繰り返す
  • 開発効率が下がる: 日本の大企業に多い異常なスローペース

GitHub Rulesetsによる解決: システムで守る

システムでちゃんと防御してあげればできることは何やってもいい

  • 間違えたらGitHubが教えてくれる: 怒られるのではなく、システムが止めてくれる
  • 「えい」ってやってみることができる: 間違えても大丈夫だから、試せる
  • 質問が不要: 間違えたら自動で分かるので、いちいち確認しなくていい
  • 経験値が溜まりやすい: 失敗を恐れずに試せる = 成長が早い
  • 心理的安全性: 「これって合ってるのかな?」と不安にならない

安心して失敗できる環境: これは教育の本質です(私が教育機関で働いていた経験から)。
失敗を恐れずに試せる環境こそが、人を育てます。
ブランチ命名規則を覚えられなくても大丈夫。間違えたらシステムが教えてくれる。

具体例: 命名規則違反のブランチを作ろうとすると

従来(脅しによる教育):

  • 新人: 「test-branchって名前でいいのかな...?先輩に聞かなきゃ...」(不安)
  • 先輩: 「ダメだよ!feature/をつけないと!」(指摘)
  • 新人: 「また怒られた...」(萎縮)
  • 結果: 毎回確認しないと怖い。開発効率が下がる。

GitHub Rulesets(システムによる防御):

  • 新人: 「test-branchって名前でpushしてみよう」(試す)
  • GitHub: 「エラー: feature/* などのパターンに合わせてください」(システムが止める)
  • 新人: 「なるほど、feature/test-branchにすればいいのか」(学習)
  • 結果: 失敗を恐れずに試せる。経験値が溜まる。

プロジェクト管理の責任

効果的なプロジェクト管理には、システムやツールに対する理解が重要です。

技術的な背景を持つマネージャーは、以下のような利点があります:
システムを活用した予防: ツールや自動化で問題を未然に防げる
効果的な意思決定: 技術的な制約や可能性を理解した上で判断できる
円滑なコミュニケーション: チームメンバーとの技術的な対話がスムーズになる

重要: 技術的制限は「面倒」に感じるかもしれません。
しかし、新規参画者の目線に立てば、これは最大の親切です。
不十分な説明で「間違えるな!」と脅されるより、システムで守られて安心して試せる方が、遥かに生産的です。

よくある質問と回答

FAQ

Q1: release/* ブランチも許可している理由は?

A: Topic #4で説明したGit Flowでは、release/* ブランチは使わないと決めました。でも、将来使うかもしれないので、許可リストには入れておきました。

Q2: Adminもバイパスできないのは厳しすぎない?

A: 緊急時はRulesetを一時的に「Disabled」に変更すればOK。誰もバイパスできないことで、「自分は例外」という意識を防げます。

Q3: ~ALL + exclude ではなく、include だけではダメ?

A: できません。Rulesetsの "creation" ルールは「対象ブランチの作成を制限」するもの。「feature/* 以外の作成を制限」するには、~ALL + exclude が必要です。

Q4: ローカルではブランチを作れるのに、pushすると弾かれるのはなぜ?

A:GitHub Rulesetsはリモートリポジトリのルールだからです。ローカルでは好きな名前のブランチを作れますが、git push した瞬間にGitHubがチェックします。

参考リンク

こちらの記事もおすすめ

前の記事

#5 GitHub Rulesetsでブランチを守る - Python OSS開発記録

記事を読む

次の記事

#7 CODEOWNERSで自動レビュー割り当て - Python OSS開発記録

記事を読む

関連トピック

コメント (0)

まだコメントはありません。最初のコメントを残しませんか?

コメントを投稿

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