Git でチームと安全に協働する― .gitignore・プルリクエスト・GitHub flow

第3回から第5回で、手元のコミットを GitHub へ push できるようになりました。ここまでは「手元・個人」の Git でした。今回はそれを、チーム (そして未来の自分) との協働に広げます。

共有する場所に出す前に、覚えることが 2 つあります。

  • ひとつは、歴史に入れてはいけない物を宣言すること (.gitignore)。
  • もうひとつは、いきなり本流を変えず、提案して通すこと (プルリクエスト)。

この 2 つを束ねた進め方が GitHub flow です。

TL;DR

  • .gitignore は「歴史に入れない物 (秘密・生成物・ゴミ)」をリポジトリに宣言するファイルです。最大の落とし穴は すでに追跡中のファイルには効かない こと。
  • 秘密情報 (.env や API キー) は、一度コミットすると履歴に残り続けます。間違えて上げたら、その鍵は無効化・再発行が鉄則です。
  • プルリクエスト (PR) は「いきなり本流を変えず、提案して人やツールの目を通してから合流する」協働の作法です。gh pr create で出せます。
  • feature ブランチで作る→ PR →マージ、を繰り返すのが GitHub flow。今の主流で、AI を使った個人開発でも取り入れたい作法です。マージのときは、第5回で見た squash とブランチ削除がそのまま効きます。
  • push をきっかけに GitHub Actions で Claude Code を走らせると、PR を開いた瞬間に AI が差分をレビューしてくれます。使うのは Anthropic 公式の anthropics/claude-code-action@v1。ふだんの Claude Pro / Max サブスクのまま動かせて、セットアップは Claude Code で /install-github-app を一度打つだけです。

共有する前に .gitignore で「入れない物」を宣言する

プロジェクトには、そもそも歴史に入れてはいけない/入れたくないファイルがあります。大きく 3 種類です。

入れたくない物理由
秘密情報.env、API キー、*.pem漏洩したら大事故。一度コミットすると履歴に残り続ける
生成物 (ビルド成果)node_modules/dist/__pycache__/ソースから再生成できる。履歴に入れても無駄に膨らむだけ
環境固有のゴミ.DS_Store(Mac)、Thumbs.db(Win)、.idea/他人には無関係な OS やエディタの副産物

表の言葉を補っておきます。API キーは、外部サービス (天気 API や AI の API など) を使うときに「自分はこのアカウントだ」と示す合言葉のような文字列で、漏れると他人に勝手に使われます。ビルド成果 (生成物) は、書いたソースコードから機械が自動で組み立て直せる物 (node_modules/ は取り寄せた部品、dist/ は配布用に固めた完成品など) で、いつでも作り直せるので歴史に残す意味がありません。

表の 3 つめは、聞き慣れないかもしれません。.DS_Store は macOS がフォルダの表示設定を覚えるために勝手に作る隠しファイル、Thumbs.db は Windows が画像のサムネイルを保存する一時ファイル、.idea/ は一部のエディタ (JetBrains 系) が作る設定フォルダです。どれも自分のパソコンが自動で作る物で、他の人には関係ありません。

歴史は、プロジェクトの「正しい元」を記録する場所です。そこから再生成できる派生物や、秘密、ゴミは含めたくない。それを宣言するのが .gitignore です。

書き方は単純です。リポジトリの直下に .gitignore という名前のファイルを作り、無視したいパターンを 1 行ずつ書きます。.gitignore 自体はコミットして共有します(チーム全員で同じ無視ルールを使うため)。

# コメントは # で始める
.env # この名前のファイル
*.log # 拡張子 .log を全部
node_modules/ # このフォルダ以下すべて(末尾の / はフォルダの意味)
dist/
.DS_Store
!important.log # 例外: 先頭の ! は「これは無視しない」

効き目は、使い捨てのフォルダで一目で確かめられます。

mkdir ignore-lab && cd ignore-lab && git init -b main
printf 'SECRET=123\n' > .env
printf 'console.log(1)\n' > app.js
git status # → .env も app.js も「追跡されていない」として出る
echo '.env' > .gitignore
git status # → .env は消え、app.js と .gitignore だけが出る
cd .. && rm -rf ignore-lab

.gitignore に書いた瞬間、.envgit status の追跡候補から消えます。これで git add . をしても巻き込まれません。事故の予防が、たった 1 行で効くわけです。

最大の落とし穴:すでに追跡中のファイルには効かない

ここが一番つまずく所です。.gitignore が効くのは、まだ追跡されていない (Untracked) ファイルだけです。第4回で見たとおり、git add でステージング (index) に載ったファイルは「追跡中」になります。一度コミットして追跡中になったファイルは、後から .gitignore に書いても無視されません

flowchart TD Q["歴史に入れたくないファイルがある"] --> T{"もう追跡されている?<br/>git status で確認"} T -->|"まだ (Untracked)"| A[".gitignore に1行書けば<br/>もう追跡候補に出ない"] T -->|"すでに追跡中"| B["git rm --cached で追跡を外してから<br/>.gitignore に書く"]

すでに追跡中なら、まず追跡だけを外しますgit rm --cached は、index から外すだけで、手元のファイル自体は消しません。

git rm --cached .env # 追跡を外す(手元の .env は残る)
echo ".env" >> .gitignore # 無視リストに追記
git commit -m "stop tracking .env"

AI に頼むなら

この .env は秘密情報なので、これから先は git の追跡対象から外して。今後コミットされないようにして。手元の .env ファイルそのものは消さないで

この一言で、AI は .gitignore に 1 行足すだけでは済ませず、先に git rm --cached .env(追跡だけ外す。手元のファイルは残す) を走らせてから .gitignore に追記します。「すでに追跡中のファイルは .gitignore に書いても無視されない」という落とし穴を、「手元のファイルは消さないで」というひと言が避けさせます。

そして、.env を間違えてコミット済みだった場合、これで「今後は追跡しない」にはできますが、過去の履歴にはまだ残っています。本当に機密なら、その鍵は漏洩したものとして無効化・再発行するのが鉄則です (履歴からの完全消去は別作業で、git filter-repo などが要ります)。「消したから大丈夫」ではなく「漏れた前提で鍵を替える」。ここは事故対応の基本として覚えておいてください。

.gitignore はあくまで「入れない」ための予防です。それでもうっかり漏らしていないかを見張る道具も、併せて使えます。GitGuardian は、git にコミットや push された秘密情報 (API キーやトークンなど) を自動で検知して知らせてくれるサービスで、個人向けの無料枠もあります。.gitignore をすり抜けたうっかりを拾う安全網として併用できます。入れてはいけないものが、push されるとメール通知が来ます。私は何度かこれに助けられました。

なお、.gitignore をゼロから書く必要はありません。NodePython などの定番リストは github.com/github/gitignore が配布されており、gh repo create <名前> --gitignore Node のように作成時に指定もできます。

テンプレに自分の追記を足すのが定石です。.DS_Store のような「自分の環境だけ」の物は、チームの .gitignore に混ぜず、グローバル設定 (git config --global core.excludesfile ~/.gitignore_global) に逃がせます。

AI に頼むなら

この Python プロジェクト用の .gitignore を、GitHub 定番の gitignore テンプレートをベースに用意して。仮想環境や __pycache__、.env も無視するようにして

この一言で、AI は github/gitignore の Python 版テンプレートを下敷きに .gitignore を作ります(__pycache__/venv/.env は元から含まれています)。スタック名(Python・Node など)と「これも無視したい物」を伝えるだけで、定番リストに自分の追記を足した形が一度に整います。

いきなり本流を変えない:プルリクエスト

.gitignore で「入れない物」を整えたら、次は「入れる物」の出し方です。チームでは、push でいきなり main(本流) を書き換えません。代わりに使うのがプルリクエスト(PR。変更を本流に取り込む前に、提案して人やツールの目を通してもらう依頼) です。

流れはこうです。別の作業ブランチで変更を作り、それを「これ、本流に入れていいですか?」と提案する。レビューして問題なければ、本流に合流させる。第2回で「Git があるから安心して失敗できる」と書きましたが、その安心をチームの規模に広げたものが PR です。本流をいつも動く状態に保ったまま、提案だけを積み上げられます。

第3回で GitHub に上げた git-lab で、実際に PR を 1 つ出してみます。

git switch -c feat-readme
printf '\n## 使い方\n' >> README.md
git commit -am "README に使い方の見出しを追加"
git push -u origin feat-readme # feature ブランチを GitHub に上げる
gh pr create --fill # コミットからタイトルと説明を埋めて PR を作成
gh pr view --web # ブラウザで差分とレビュー画面を開く
gh pr merge --squash --delete-branch # squash でマージして、ブランチも消す

AI に頼むなら

この変更は main に直接コミットしないで。別のブランチを切ってそこで作業し、origin に上げて、PR に出せる状態にして

この一言で、AI は main を直接いじらず、git switch -c <ブランチ> で作業ブランチを切ってそこにコミットし、git push -u origin <ブランチ> まで進めて、gh pr create で PR を出せる状態に整えます。「main に直接じゃなく」「PR に出せる状態に」と言うだけで、本流を守る GitHub flow の入口に乗ります。

最後の gh pr merge --squash --delete-branch は、第5回で見た「squash でまとめる」と「マージ後にブランチを削除する」を、PR の取り込みで一度にやっています。雑な作業コミットを 1 つにまとめて本流へ入れ、用済みのブランチを片付ける、という流れがそのまま乗っています。

「自分ひとりのプロジェクトなのに PR は要る?」と思うかもしれません。ひとりでも回す価値はあります。feature ブランチで作って、自分宛てに PR を出し、GitHub の差分画面で全体を見渡してからマージする。とくに AI に変更を作らせたときは、この差分画面が「何を変えたのか」をまとめて点検する場になります。いきなり main に入れる前に、一度引いて眺める癖がつきます。

チームでは、他の人の変更も PR の形で届きます。相手が fork(他人のリポジトリを自分のコピーとして複製すること) で作った変更が PR として送られてきたら、GitHub の「Files changed」タブで差分を確かめてから取り込みます。送るのも受け取るのも、同じ「提案して、見てから合流」の作法です。

それを束ねる型:GitHub flow

ここまでの「feature で作る→ PR を出す→レビュー→本流にマージ」を、ぐるぐる回す進め方に名前が付いています。GitHub flow です。

flowchart TD M["main<br/>常にデプロイ可能"] --> F["feature を切る<br/>作業する"] F --> P["PR を出す<br/>これ入れていい?"] P --> R["レビュー<br/>人 / CI / AI"] R --> G["main にマージ<br/>ブランチは削除"] G --> M

ここで出てくる CI(push のたびに、テストなどを自動で走らせる仕組み) は、次のセクションで実際に動かします。デプロイ (本番環境へ反映すること) はもっと先の話ですが、まず CI に AI のレビューを乗せる形を先に見ておきましょう。main はいつでも動く状態に保ち、変更はすべて短命な feature と PR を通す。これが GitHub flow の骨格です。

似た名前で Git flow という、もっと重厚な型もあります。違いはブランチの数です。

GitHub flow(シンプル・主流)Git flow(重厚・厳密)
ブランチmain +短命な feature だけmain / develop / feature / release / hotfix
流れfeature で作業→ PR →レビュー→ main にマージdevelop に集約→ release で固める→ main はリリース版だけ
思想main は常にデプロイ可能。小さく速くリリースを段階的に厳密管理
向くWeb・SaaS など継続的に出す開発パッケージや組み込みなど版管理が重い開発

今の主流は GitHub flow です。Git flow は多くの現場で「重すぎる」とされ、簡略版に流れています。入門記事の中には Git flow を丁寧に教えるものもありますが、個人開発や AI と組む小回り重視なら、まず GitHub flow を覚えれば十分です。

第3回で触れた「AI に作らせて、気に入らなければブランチごと捨てる」も、この GitHub flow の上に自然に乗ります。型を増やしすぎないことも、ひとつの判断です。

push したら AI がレビューに加わる:GitHub Actions に Claude Code を組み込む

GitHub flow の図に 「レビュー=人 / CI / AI」 と書きました。その「CI」と「AI」を、ここで実際に動かします。push して PR を開いた瞬間に、GitHub のサーバーが Claude Code を起動し、差分を読んでレビューコメントを返す。人がレビューに入る前の一次チェックを、AI に任せられます。

使うのは GitHub Actions(push や PR をきっかけに、GitHub のサーバー上で決めた処理を自動で走らせる仕組み) です。テストの自動実行やデプロイで定番の機能ですが、ここにもう一段、AI のレビューを乗せます。

その AI レビューの中身が Claude Code です。Anthropic が公式に配っている GitHub Action (anthropics/claude-code-action公式ドキュメント) を使うと、PR に @claude とコメントして対話的に頼んだり、PR が開かれたら自動でレビューさせたりできます。

まずセットアップ:コマンド 1 つで足場を作る

いちばん簡単なのは、手元の Claude Code を開き、以下のコマンドを実行することです。

/install-github-app

これで、GitHub App(リポジトリに権限を与えて常駐させる連携アプリ) の導入と、認証情報をリポジトリの シークレット(API キーなどの秘密の値を、コードに直書きせず GitHub に預けて参照する仕組み) に登録するところまで、対話でガイドしてくれます。実行にはリポジトリの管理者権限が要ります。

認証は 2 通りから選べます。うれしいのは、ふだん使っている Claude Pro / Max のサブスクリプションでそのまま動かせることです。手元の Claude Code で次を実行すると、サブスクに紐づく OAuth トークン (サブスクの認証を肩代わりする使い捨ての鍵) が出ます。

claude setup-token

出てきたトークンを、リポジトリの Secrets に CLAUDE_CODE_OAUTH_TOKEN という名前で登録します。これならコード生成ぶんの API 料金は別途かからず、サブスクの枠内で動きます。もう 1 つは従量課金の API キー (ANTHROPIC_API_KEY) で、使った分だけ課金される方式です。どちらを選んでも、ワークフロー側の書き方はほぼ同じです。

手で設定するなら 3 ステップです。

  1. Claude の GitHub App (github.com/apps/claude) を対象リポジトリに入れる
  2. 認証トークンを Secrets に登録する (サブスクなら CLAUDE_CODE_OAUTH_TOKEN、API キーなら ANTHROPIC_API_KEY)
  3. ワークフローファイル (自動処理の中身を書いた設定ファイル) を .github/workflows/ に 1 つ置く

App に渡す権限は Contents・Issues・Pull requests の読み書きです。ここは .gitignore.env を歴史に入れなかった話と地続きで、鍵はワークフローにもベタ書きしません。後で出てくる ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} のように、預けた値を参照します。

@claude と話しかけて呼ぶ

定番は、PR やイシューのコメントで @claude と呼ぶ形です。公式ドキュメントにある最小のワークフロー(YAML=設定を字下げで書くテキスト形式) を、リポジトリに .github/workflows/claude.yml という名前で置きます。中身はこれだけです。

name: Claude Code
on: issue_comment: types: [created] pull_request_review_comment: types: [created]
jobs: claude: runs-on: ubuntu-latest steps: - uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} # コメント内の @claude メンションに反応する

これで、PR のコメント欄から日本語でそのまま頼めます。従量課金の API キーで動かしたいなら、claude_code_oauth_token: の行を anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} に差し替えるだけです。

@claude このPRの差分をレビューして、バグと抜けを日本語で指摘して
@claude このエラーの原因になっていそうな箇所はどこ?

@claude を見つけると Action が起動し、Claude Code が差分や文脈を読んで、コメントで返事を書きます。

メンションも省く:PR を開いたら自動でレビュー

毎回 @claude と打つのも省きたいなら、PR が開かれた瞬間に自動で走らせます。公式の「prompt を直接渡す」書き方を応用して、私はこう置いています。

name: PR 自動レビュー
on: pull_request: types: [opened, synchronize]
jobs: review: runs-on: ubuntu-latest steps: - uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} prompt: "このPRの差分をレビューして、バグ・セキュリティ・可読性の3点で、日本語で具体的にコメントしてください"

on: pull_requesttypesopened(新しく開いたとき) と synchronize(その PR に後から push を足したとき) を入れているので、PR を出した瞬間も、直してまた push したときも、そのつどレビューが走ります。

レビューの観点を毎回 prompt に書くのが面倒なら、リポジトリ直下に CLAUDE.md(プロジェクトの約束事を書いておくと Claude が従う設定ファイル) を置き、コードスタイルやレビュー基準をそこへ集約できます。.gitignore と同じく、これもコミットしてチームで共有するファイルです。

便利だが、ただではない

最後に注意を 2 つ。

1 つはお金です。Claude 側は、サブスクの OAuth トークンで動かすならサブスクの枠内で済みますが、従量課金の API キーを使う場合は、やり取りした分のトークン (文章の分量に応じて決まる課金単位) が積み上がります。そして認証がどちらでも、GitHub Actions の実行時間 (GitHub のサーバーを借りるぶん) は別途かかります。暴走を防ぐため、claude_args--max-turns(AI の往復回数の上限) を絞り、ワークフローにタイムアウトを設定しておきます。

もう 1 つは鍵の扱いです。OAuth トークンも API キーも、必ず Secrets 経由 (${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} など) で渡し、ワークフローに直書きしない。これは公式も繰り返し注意しています (コストと安全の項)。

これで GitHub flow の「レビュー」に、24 時間動く一次チェックが加わりました。人は AI が拾った後の、設計やトレードオフの判断に集中できます。第3回の「AI に作らせて差分で点検する」癖が、PR ごとに自動で回る仕組みに変わるわけです。1 人プロジェクトでも、PR を出すたびに「もう一人の目」を雇えます。

困ったときの早見表

協働していると、手が止まる場面が出ます。ここまでの回で扱った対処を、表にまとめておきます。

git stash だけ初登場なので一言だけ。まだコミットしたくない作業を、一時的に棚へ預けて手元を綺麗にするコマンドです。別の急ぎ作業に切り替えたいときに、git stash で預け、戻ったら git stash pop で取り出します。

困りごと対処扱った回
まだコミットしてない変更を一時退避したいgit stash →後で git stash pop(今回の補足)
間違えて git add したgit restore --staged <ファイル>第5回
直前のコミットの内容やメッセージを直したいgit commit --amend(共有前だけ)第5回
コミットを取り消したいgit reset(巻き戻す)/ git revert(打ち消しを足す)第5回
消してしまった・戻したいまず git reflog第5回
ブランチが溜まったgit fetch --prunegit branch -d第5回

AI に頼むときの言い方

協働の作法も、AI への頼み方を具体的にしてくれます。コマンドは AI に打たせるとしても、何をどう扱ってほしいかを言葉にできると、結果がまっすぐ返ってきます。

✗曖昧な頼み方◯的確な頼み方裏で動く操作
「秘密のファイルが上がらないようにして」.envnode_modules.gitignore に入れて」.gitignore に追記 (追跡済みなら git rm --cached)
「これ GitHub に反映して」「この変更は main に直接じゃなく、PR にして出して」feature ブランチ→ push → gh pr create
「PR 作っといて」「PR の説明文を、何をなぜ変えたか分かるように書いて」gh pr create の本文を整える
「PR を自動でチェックしたい」「PR を開いたら Claude Code が差分をレビューする GitHub Actions を作って」anthropics/claude-code-action@v1 のワークフローを .github/workflows/ に置く

どれも、入れない物・本流に直接入れない・提案の形にする、という協働の言葉で頼んでいるだけです。この語彙があると、AI は迷いません。

まとめ

第 6 回として、手元の Git を、チームと未来の自分に向けて開きました。

  • .gitignore は「歴史に入れない物 (秘密・生成物・ゴミ)」を宣言するファイル。最大の落とし穴は すでに追跡中のファイルには効かない こと。外すには git rm --cached
  • 秘密を間違えてコミットしたら、消すだけでなく 鍵を無効化・再発行する。履歴には残るからです。
  • プルリクエストは、いきなり本流を変えず、提案して目を通してから合流する作法。ひとりでも、差分を引いて眺める場として効く。
  • feature → PR →マージを回すのが GitHub flow。今の主流で、個人開発でも十分。マージは第5回の squash とブランチ削除がそのまま乗る。
  • GitHub Actions × Claude Code で、PR を開いた瞬間に AI レビューを走らせられる。人のレビュー前の一次チェックを自動化でき、1 人開発でも「もう一人の目」になる。公式の anthropics/claude-code-action@v1.github/workflows/ に置くだけ。

次回は最終回です。git worktree を扱います。1 つのリポジトリで、複数の作業場所を同時に持つ仕組みで、AI エージェントに別々の作業を並行で進めさせるときに効いてきます。「ブランチは 40 文字のしおり」という第3回の理解が、ここでもう一度効きます。