Git / GitHubを実務で使うとき、最初に理解したいこと

コードを本番に出す。障害が起きたら戻す。担当が変わっても保守を続ける。

どの場面でも「いつ、誰が、何を、なぜ変えたか」を追える状態が前提になります。GitとGitHubは、この状態を作る道具と基盤です。

この記事では開発フローを一周しながら全体像をつかみます。用語は登場する場面で定義するので、頭から読み進めてください。

目次

前提整理:概念とツールを分ける

Git、GitHub、CI/CDは現場でよく混同されます。最初に「ツール」と「概念」を切り分けておきます。

Gitはバージョン管理ツールです。手元のファイル変更を履歴として刻み、過去の任意の状態に戻れるようにします。PCにインストールして使うローカルのソフトウェアであり、GitLabやBitbucketでもGitそのものは共通です。

GitHubはGitの履歴をチームで共有するクラウドプラットフォームで、レビュー、承認、自動チェック、権限制御を一箇所に集約できます。

CI/CDはツールではなく、開発プロセスの概念です。GitHub ActionsやJenkinsはCI/CDを実現するためのツールにすぎません。

CIとCDの違い

CI(Continuous Integration)は、変更を小さく保ち、頻繁にmainブランチへ統合する考え方です。統合のたびにビルドとテストを自動実行し、問題を大きくなる前に検知します。

CDには二つの意味があります。Continuous Deliveryは確認済みの変更をいつでもリリースできる状態に保つこと。Continuous Deploymentは確認済みの変更を自動で本番に出すこと。現場では両方をまとめてCDと呼ぶことが多いため、どちらを指すかは文脈で判断してください。

実務の基本形

「チームやプロジェクトによる」で済ませると標準がなくなります。以下は多くの現場で採用されている開発の基本形です。

  1. Issueで作業を定義する
  2. mainからブランチを切る
  3. 変更を意味単位でcommitする
  4. リモートにPushする
  5. Pull Requestを開く
  6. CIで自動チェックを通す
  7. レビューを受けて承認をもらう
  8. mainにマージする
  9. タグまたはReleaseでリリース境界を残す

次の節でこの流れを各ステップの中身まで掘り下げます。各ステップで「何が記録されるか」「何を防いでいるか」に注目してください。

開発フローを一周する

Issueで作業を定義する

コードを書き始める前にIssueを作ります。書く項目は三つ。背景(なぜこの変更が必要か)、完了条件(何ができたら終わりか)、影響範囲(どの機能やシステムに波及するか)。

起票しないまま作業を始めると「なぜ変えたか」が残りません。障害調査や引き継ぎで理由を遡れなくなります。

GitHubにはIssueの他にも管理機能があります。Projectは複数Issueを並べて進捗や優先度を見る器。DiscussionはまだIssueにできない段階の相談の場。Topicはリポジトリ自体の分類タグです。Issueが「作業単位」、Projectが「一覧表示」という関係を押さえておけば混同しません。

ブランチを切る

mainブランチから作業用のブランチを作ります。mainは本番に出せる品質を保つブランチです。ブランチを分けることで、レビュー前の変更がmainに混ざる事故を防ぎます。

ここでHEADが登場します。HEADは「自分が今どのブランチのどのコミットにいるか」を指すポインタです。git switchgit checkoutでブランチを切り替えると、HEADの先が変わります。HEADの位置=自分の作業位置、と覚えてください。

commitで変更を刻む

ファイルを編集したら、変更を履歴に刻む操作がcommitです。Gitでは二段階に分かれています。

  1. git add — 変更をステージング領域に載せる。「次のcommitに含める変更を選ぶ」操作。
  2. git commit — ステージングの内容を確定し、履歴として残す。

commitは「ファイルの保存」とは異なります。保存はファイルの上書き。commitは「この変更を、この理由で確定した」という記録の単位です。1つのcommitが1つの変更意図に対応するのが理想。粒度が後の障害調査やレビューの品質を左右します。

commitを作るとcommit SHAが割り当てられます。commit SHAは、そのcommitを一意に特定する40文字のハッシュ値です(例: a1b2c3d4e5...)。障害調査で「原因はこのcommit」と指すとき、git show a1b2c3dで中身を確認するとき、commit SHAを使います。

Pushでリモートへ送る

ローカルのcommit履歴をGitHub(リモートリポジトリ)へ送る操作がPushです。Pushした時点で、チームにその変更が見えるようになります。

ここで最初のセキュリティチェックが入ります。GitHubのsecret scanning / push protectionが有効なら、APIキーやトークンを含むcommitはPush時にブロックされます。秘密情報の漏えいは「うっかりcommit→Push」で起きることが大半です。Push時点で止めることで被害を防ぎます。ただし、独自形式のパスワードなど検知対象外のパターンもあるため、過信は禁物です。

Pull Requestを開く

「この変更をmainに入れてよいか」をチームに問う仕組みがPull Request(PR)です。PRを開くと、変更差分・説明・レビュー・承認が一箇所に集まります。

PR本文には、変更理由(対応Issueへのリンク)、確認方法(テスト手順)、ロールバック方針を書きます。これが障害調査や監査で参照する証跡になります。

Draft PRで作業途中から開くこともできます。完成後に開くと方向修正のコストが跳ね上がるため、早めに共有する方が合理的です。

CIが走る:GitHub Actionsによる自動チェック

PRを開くと、GitHub Actionsが自動でビルド・テスト・静的解析を実行します。これがCIの実体です。「人がマージする前に、機械で止められるものは止める」仕組みになります。

GitHub Actionsの構造は4層です。外側からWorkflowJobStepActionの順に入れ子になっています。Workflowは自動処理全体の定義で、.github/workflows/にYAMLファイルとして置きます。Jobは処理のまとまり、Stepは実行単位、Actionは再利用可能な部品。Event(pull_request、pushなど)をきっかけにWorkflowが起動します。

CI以外にも、Dependabot(脆弱な依存関係の検出と更新PR自動作成)やcode scanning(静的解析によるセキュリティ欠陥検出)がActionsと連携して動きます。これらのリスクと限界については「セキュリティをフローに組み込む」節で詳しく扱います。

レビューと承認

PRに対して技術レビュー(コードの正しさ)と業務レビュー(仕様の正しさ)を受けます。Review履歴は「誰が何を確認したか」の証跡であり、監査でそのまま使えます。

GitHubではbranch protectionまたはrulesetでレビューを強制できます。

  • 必須レビュー — 承認なしではマージ不可。「誰も見ていない変更がmainに入る」事故を防ぐ。
  • 必須チェック — CIが通るまでマージ不可。壊れた状態がmainに入ることを防ぐ。
  • 会話の解決必須 — 未解決コメントがある間はマージ不可。
  • 署名付きcommit必須 — 改ざん検知と責任追跡のため。

Rulesetはbranch protectionの上位互換で、複数ルールを組み合わせて適用できます。ファイルパスやサイズの制限もPush単位で掛けられます。

アクセス管理も重要です。Teams、Roles、CODEOWNERSで「誰がどこを見て、書いて、承認できるか」を制御します。退職者アカウントにmain書き込み権限が残っていた、という事故は権限の定期棚卸しで防ぎます。

マージ

PRの変更をmainに取り込む操作がマージです。GitHubでは三つの方式を選べます。

  • merge commit — ブランチの流れとマージ点が履歴に残る。commit経緯をそのまま保ちたいとき向き。
  • squash merge — PR内の全commitを1つにまとめる。mainの履歴を短く保ちたいとき向き。
  • rebase merge — 各commitを一直線に並べ直す。commit粒度を保ちつつ線形にしたいとき向き。

チームで方式を決めてCONTRIBUTINGに明記してください。方式が混在するとmainの履歴が読みにくくなり、障害調査で変更単位を追う際に支障が出ます。

コンフリクト

マージやrebase中に、同じ箇所を別々に変更していた場合、Gitが自動で統合できないことがあります。これがコンフリクトです。

<<<<<<< HEAD
if user == nil
=======
if user === nil
>>>>>>> fix/login-message

上側がHEAD(今のブランチ側)、下側が取り込む側です。rebase中はこの対応が直感とずれることがあるため、どのcommitを再適用中か確認してください。

解消の目的は「マーカーを消す」ことではなく「仕様として正しい状態に収束させる」こと。IssueやPR本文で双方の変更意図を確認し、業務要件に照らして判断します。

リリース

mainにマージされた変更を本番に出す段階です。タグまたはReleaseで「どのcommitまでが本番にいるか」を記録します。障害発生時に切り戻し範囲を即座に特定するためです。

CDとして、mainマージを起点にデプロイを自動実行する構成もあります。GitHub ActionsのEnvironment設定で承認者を挟めば、本番デプロイ前に人の判断を入れることもできます。

セキュリティをフローに組み込む

セキュリティを最後にまとめて確認すると、発見時には既にmainへ入り本番に出ていることがあります。変更がmainに入る前に止められるものは、その時点で止めるのが原則です。開発フローの各ステップで触れた機能を、リスクの観点から整理します。

秘密情報の漏えい

APIキーやトークンをうっかりcommitし、そのままPushする事故は頻度・被害ともに大きいリスクです。secret scanning / push protectionが最初の防壁になりますが、独自形式のパスワードや環境変数名に隠れた秘密情報は検知対象外になることがあります。カスタムパターンの登録で範囲を広げられますが、網羅はできません。

漏えいが起きた場合、最初にやることはその資格情報の無効化またはローテーションです。コミットを消しても資格情報が有効なら攻撃は止まりません。対応順序は以下のとおりです。

  1. 漏えいした資格情報を即座に無効化・ローテーションする
  2. 影響範囲を特定する(いつからいつまで有効だったか、アクセスログに不審な操作はあるか)
  3. Gitの履歴から秘密情報を除去する(git filter-repoまたはBFG Repo-Cleaner)
  4. 再発防止策を実施する(push protectionの有効化、カスタムパターンの追加、pre-commitフックの導入)

脆弱な依存関係

既知の脆弱性を持つライブラリを放置すると、その経路から侵入されるリスクがあります。Dependabotはdependency graphをもとに脆弱性を検出し、更新PRを自動作成します。

更新PRをすべて即座にマージする必要はありません。CVSSスコアや影響範囲を見て優先度を判断してください。互換性を壊す更新もあるため、CIでテストが通ることを確認してからマージします。ゼロデイやdependency graphに載らない間接依存は検出対象外です。

危険なコードの検出

code scanningは静的解析でSQLインジェクション、XSS、パストラバーサル等のパターンを検出します。PR差分に対して走るため、マージ前に指摘を受けられます。

静的解析は既知のパターンに基づくため、ビジネスロジック上の脆弱性や未知の攻撃パターンは拾えません。誤検知もあります。指摘を鵜呑みにせず、修正の要否はコードの文脈を読んで判断してください。

権限の管理と棚卸し

退職者アカウントにmain書き込み権限が残っていた、BotにWrite権限を渡したまま放置していた、という事故は現場で起きています。Teams、Roles、CODEOWNERSで権限を定義し、定期的に棚卸ししてください。

audit logはOrganizationレベルで「誰がいつ設定を変えたか」を記録します。事後調査だけでなく、変更の検知にも使えます。

GitHubリポジトリの設定

リポジトリの設定は多いですが、どれも運用のどこかに効きます。全部を一度に有効化する必要はありません。ただし、何を制御できるかを知らないと、事故を止める手段を持てません。以下の表で設定カテゴリの全体像をつかんでください。「何を制御するか」列で、そのカテゴリが運用のどこに効くかが分かります。

カテゴリ代表項目何を制御するか
リポジトリ基本説明、README、デフォルトブランチ、可視性、Topics、Issues / Projects / Discussions / Wiki の有効化そのリポジトリが何者か、何の機能を使うか
PRとマージmerge commit / squash / rebase許可、auto-merge、コミットメッセージ形式、head branch自動削除mainへどんな履歴を残すか
ブランチ保護・ruleset必須レビュー、必須チェック、会話解決、署名、線形履歴、merge queue、deployment成功必須、Push制限mainへ何を入れてよいか、誰が触れるか
アクセス管理Collaborators、Teams、Roles、CODEOWNERS、Bypass権限、Apps誰が見て、書いて、承認できるか
ActionsAllowed actions、Workflow permissions、Secrets、Variables、Runners、Environmentsどこまで自動化し、どんな権限で動かすか
SecurityDependency graph、Dependabot、secret scanning、push protection、code scanning、audit log脆弱性・秘密情報・危険コードの検知と証跡
連携・配布Webhooks、GitHub Apps、Releases、Packages、Pages外部連携、配布、通知

ブランチ保護とrulesetの主要項目

Require pull request reviews before merging: 承認なしでmainへ入らないようにします。必要承認数、CODEOWNERSレビュー必須、stale approvalの扱い、直近Pushに対する他者承認必須を制御できます。

Require status checks before merging: テスト・ビルド・静的解析が通るまでマージ不可にします。厳格運用では、ベースブランチへ追従した最新状態で再実行を求めます。

Require conversation resolution before merging: PR上の未解決コメントが残っている間はマージ不可にします。

Require signed commits: 署名付きコミットだけを受け入れます。改ざん検知と責任追跡に効きます。

Require linear history: マージコミットを禁止し、squashかrebaseだけを許可します。

Require merge queue: 複数PRを安全に順番待ちさせながら統合します。頻繁にmainが動くリポジトリ向けです。

Require deployments to succeed before merging: staging等へのデプロイ成功をマージ条件にできます。

Rulesetはbranch protectionより広く、複数ルールを重ねて適用できます。Push rulesetでファイルパス・拡張子・サイズの制限も掛けられます。

リポジトリ基本設定とPull Request設定

説明、ホームページURL、README: リポジトリの目的と入口を示します。引き継ぎと棚卸しで効きます。

Default branch: mainをどこに置くかの基準です。Actions、PR、保護設定の前提になります。

Topics: 技術、業務領域、用途、所有チームを分類します。検索性に効きます。

Issues / Projects / Discussions / Wiki: そのリポジトリで何をGitHub上に残すかを決めます。

Allow merge commit / squash merge / rebase merge: 利用可能なマージ方式を制御します。branch ruleと矛盾するとマージできません。

Auto-merge: 条件がそろったら自動でマージします。

Automatically delete head branches: マージ後に作業ブランチを自動削除し、残骸を減らします。

Actions・Secrets・Environmentの設定

Allowed actions and reusable workflows: 利用可能なActionを制限します。信頼できる提供元だけに絞ることでサプライチェーン攻撃のリスクを下げられます。

Workflow permissions: GITHUB_TOKENの権限範囲を決めます。基本は最小権限です。広すぎる権限を渡すと、悪意あるActionがリポジトリ設定やSecretにアクセスする経路になりえます。

Secrets / Variables: APIキーや設定値を安全に渡します。Secretはログに伏せ字で出ますが、意図的にechoすれば見えるため、Workflow内容もレビュー対象にしてください。

Environments: staging・本番など環境ごとの秘密情報、承認者、待ち時間、デプロイ保護を持てます。承認者を設定すると、デプロイ前に人の判断を挟めます。

Runners: GitHub-hosted runnerかself-hosted runnerかで、ネットワーク到達性、コスト、セキュリティ境界が変わります。社内ネットワークへのデプロイにはself-hosted runnerが必要ですが、runner自体の保守とセキュリティ管理も発生します。

記録が活きる場面

ここまでの設定とフローが整っていると、日常の開発以外の局面で効果が出ます。特に差が出るのは引き継ぎ、障害調査、監査の三つです。

引き継ぎ

新しい担当者がリポジトリを受け取ったとき、最初に見るのはREADME(目的、起動方法、関連資料、窓口)とCONTRIBUTING(ブランチ命名、コミット粒度、レビュー基準、リリース手順)です。次にIssue、Pull Request、直近Release、main保護やCODEOWNERSの設定を見ると、運用の実態が分かります。

これらが書かれていないリポジトリでは、前任者への属人的なヒアリングに頼ることになります。

障害調査

直近のPull Request、コミット、タグ、Releaseから対象範囲を狭めます。コミットが小さく、PR本文に確認方法とロールバック方法が残っているほど、原因特定と復旧判断は速くなります。

commit SHAでピンポイントに原因を指し、revertで戻すか、cherry-pickで修正だけ適用するかを判断します。commit粒度が粗いと、この判断の精度が落ちます。

監査

誰が承認したか、どのチェックを通したか、いつ設定を変えたかが問われます。Review履歴、Actions実行結果、ruleset設定、audit logがそのまま説明材料になります。事後に説明を組み立てるのでなく、普段の運用が自動的に証跡になる点が重要です。

フローの中で使う用語

開発フローの途中で使うことになるが、フローの必須ステップではない操作を整理します。

commit –amend

直前のcommitにステージング中の変更を追加したり、メッセージを修正したりする操作です。まだPushしていないcommitの修正に使います。Push済みのcommitに使うと履歴を書き換えるため、force pushが必要になり、他の開発者の作業と食い違います。

cherry-pick

別ブランチから特定のcommitだけを持ってくる操作です。ホットフィックスをmainから安定版ブランチへ移すときに使います。そのcommitが依存する別のcommitまでは持ってこないため、適用後にビルドとテストで検証してください。

revert

指定したcommitの効果を打ち消す新しいcommitを作ります。履歴を消さないため、共有済みブランチで安全に使える切り戻し手段です。mainにマージ済みの変更を取り消す場合、通常revertが最初の候補になります。

restoreとreset

どちらも「戻す」操作ですが対象が違います。

  • restore — 作業ディレクトリやステージの変更を捨てる。ファイル単位の取り消し。
  • reset –soft — HEADだけ戻す。変更はステージに残る。commitのやり直しに使う。
  • reset –mixed — HEADを戻し、変更を作業ディレクトリへ戻す。commitの分け直しに使う。
  • reset –hard — すべて戻す。ローカルにしかない変更を完全に消したいとき限定。

選ぶ基準は共有状態です。ローカルならrestore/reset、共有済みならrevert。Push済みブランチにreset –hardを使うと他の開発者の履歴と食い違います。

stashとreflog

stashは未commitの変更を一時退避する操作です。pullやrebase前に作業をよけるときに使います。長期保管には向きません。

reflogはローカルでHEADがどこを指していたかの履歴です。resetやrebaseで迷子になったとき、元の位置を探すのに使います。ローカル限定の記録であり、共有の証跡にはなりません。

フローと用語を一通り押さえたところで、現場で混同されやすいポイントを整理します。

よくある誤解

「Git=GitHub」ではない

前提整理で区別しましたが、混同すると実務で判断を誤ります。Issue、Pull Request、Actions、branch protectionはすべてGitHub側の機能であり、Gitだけでは使えません。逆に、commitやブランチ操作はGit側の機能なので、GitHubが停止していてもローカル作業は続行できます。障害時にどこまで動けるかの判断に関わる区別です。

「CI/CDはツール」ではない

GitHub Actionsを入れただけでは「CI/CDを導入した」とは言えません。小さい変更を頻繁に統合し、テストを毎回通し、リリース可能な状態を常に保って初めてCI/CDになります。ツールだけあってプロセスが伴わない現場では、Actionsがただのビルド実行機になりがちです。

「commit=保存」ではない

「とりあえずcommit」で粒度の粗い履歴になると、障害調査でcommit SHAから原因を追えません。revertで特定の変更だけ戻したいとき、cherry-pickで特定の修正だけ持ってきたいとき、粒度が粗いと範囲が広すぎて使いものになりません。1 commitに1つの変更意図を対応させる習慣が重要です。

「rebaseは常にmergeより良い」わけではない

rebaseは履歴を直線にしますが、共有済みブランチに使うと他の開発者の履歴と矛盾します。force pushが必要になり、レビュー済みの差分が壊れることもあります。ローカルの整理にはrebase、共有ブランチにはmergeが安全です。

まとめ

理解したこと

  • Gitは変更履歴を刻むツール、GitHubはそれを共有しレビュー・自動チェック・権限制御を重ねる基盤。
  • 開発フローは Issue → ブランチ → commit → Push → PR → CI → レビュー → マージ → リリース の一周。
  • 各ステップで「何を記録し、何を防いでいるか」が運用の品質を決める。
  • セキュリティは後付けでなく、Push時・PR時・マージ時に組み込む。

最初の一歩

  1. README・CONTRIBUTING・テンプレートを用意する — READMEには目的・起動方法・関連資料・窓口。CONTRIBUTINGにはブランチ命名・コミット粒度・レビュー基準・リリース手順。IssueとPRテンプレートには背景・完了条件・確認方法・影響範囲を並べます。
  2. mainへの直接Pushを止め、PR経由にする — branch protectionまたはrulesetで設定します。すべての変更がPRを経由すると、差分・レビュー・承認がPR単位で自動的に残ります。
  3. レビューと自動チェックを必須にする — 必須レビュー1件以上、Actionsでビルドまたはテスト最低1本。「誰も見ていない変更がmainに入る」事故と「壊れた状態がmainに入る」事故を同時に防ぎます。
  4. マージ方式を決めて明文化する — merge commit・squash・rebaseのどれを使うかをCONTRIBUTINGに書きます。決めないまま運用するとmainの履歴が混在し、障害調査時に変更単位を追いにくくなります。
  5. secret scanning・Dependabot・code scanningを順に有効化する — secret scanningとpush protectionで漏えいを防ぎ、Dependabotで脆弱な依存を検知し、code scanningで危険なコードを検出します。いずれも有効化するだけで動き始めます。
  6. リリース境界をタグまたはReleaseで残す — 本番反映時にタグを打つか、Releaseを作ります。障害時に「どのcommitまでが本番にいるか」を即座に特定でき、切り戻し範囲の判断が速くなります。
  7. 案件が並ぶならProjectで一覧する — 複数IssueやPRが同時に進む場合、Projectのボードまたは表で優先度・担当・ステータスを一覧にします。

ここまでの設定が回ると、障害時に「いつ、誰が、何を、なぜ変えたか」をPRとIssueの番号で追えます。引き継ぎではREADMEとCONTRIBUTINGから運用が分かり、監査ではReview履歴とActions結果がそのまま証跡になります。

仕組みを理解した上で、次は実際にリポジトリを作り、ブランチ → commit → PR → マージの流れを手元で確認してみてください。

目次