Skilore

バージョン管理

Git を使いこなすことは現代のソフトウェアエンジニアにとって「読み書き」と同じレベルの基本スキルである。

83 分で読めます41,419 文字

バージョン管理

Git を使いこなすことは現代のソフトウェアエンジニアにとって「読み書き」と同じレベルの基本スキルである。

この章で学ぶこと

  • Gitの内部モデル(DAG)を理解する
  • ブランチ戦略を説明できる
  • 実務でのGitワークフローを知る
  • コミットメッセージの書き方を習得する
  • マージとリベースの使い分けを理解する
  • コンフリクト解決の手順を身につける
  • Git Hooksによる自動化を学ぶ
  • CI/CDとの連携パターンを理解する
  • 大規模リポジトリの運用ノウハウを知る
  • トラブルシューティングの実践的テクニックを習得する

前提知識

このガイドを読む前に、以下の知識があると理解が深まります:

  • 基本的なプログラミングの知識
  • 関連する基礎概念の理解
  • システム設計入門 の内容を理解していること

1. Gitの内部モデル

1.1 DAGとオブジェクトモデル

Git = 有向非巡回グラフ(DAG)+ コンテンツアドレスストレージ

  コミット: スナップショット(ファイル全体のツリー)
  ブランチ: コミットへのポインタ(ただの参照)
  HEAD: 現在のブランチ/コミットへのポインタ

  DAG構造:
  C1 ← C2 ← C3 ← C4      main
                 ↖
                  C5 ← C6  feature

  各コミットは親コミットのハッシュを保持
  → 改ざん不可能な履歴チェーン(ブロックチェーンと同原理)

  オブジェクトモデル:
  - blob: ファイルの内容(SHA-1ハッシュ)
  - tree: ディレクトリ(blobとtreeへの参照)
  - commit: ツリー + 親コミット + メタデータ
  - tag: コミットへの名前付き参照

1.2 オブジェクトモデルの詳細

Gitの4つのオブジェクト型:

  1. blob(Binary Large Object)
blob 15\0Hello, World!\n
SHA-1: af5626b4a114abcb82d63db
- ファイルの中身そのもの
     - ファイル名を含まない(名前はtreeが管理)
     - 同じ内容のファイルは1つのblobを共有

  2. tree(ディレクトリに相当)
tree
100644 blob a1b2c3... README.md
100644 blob d4e5f6... main.py
040000 tree 7a8b9c... src/
- ファイル名とモード(パーミッション)を保持
     - 子のblobやtreeへの参照

  3. commit
commit
tree d8329fc...
parent a0b1c2d...
author Alice <alice@example.com> 1234567890
committer Alice <alice@example.com> 1234567890
Add user authentication feature
- ルートtreeへの参照
     - 親コミットへの参照(マージコミットは2つ以上)
     - 作者とコミッター(別人の場合がある)
     - コミットメッセージ

  4. tag(annotated tag)
tag
object e3f4a5b...
type commit
tag v1.0.0
tagger Alice <alice@example.com> 1234567890
Release version 1.0.0
# オブジェクトモデルを実際に確認するコマンド
git cat-file -t HEAD        # オブジェクトの型を表示
# commit
 
git cat-file -p HEAD        # オブジェクトの中身を表示
# tree d8329fc...
# parent a0b1c2d...
# author Alice <alice@example.com> 1704067200 +0900
# committer Alice <alice@example.com> 1704067200 +0900
#
# Add user authentication feature
 
git cat-file -p HEAD^{tree}  # ルートtreeの中身
# 100644 blob af5626b... README.md
# 040000 tree 7a8b9c0... src
 
git cat-file -p af5626b      # blobの中身
# (ファイルの内容が表示される)
 
# オブジェクトの格納場所
ls .git/objects/
# af/  7a/  d8/  ...
# 最初の2文字がディレクトリ名、残りがファイル名

1.3 参照(References)の仕組み

参照の種類:

  1. ブランチ参照
     .git/refs/heads/main          → コミットハッシュ
     .git/refs/heads/feature/login → コミットハッシュ

  2. リモート追跡参照
     .git/refs/remotes/origin/main → コミットハッシュ

  3. タグ参照
     .git/refs/tags/v1.0.0         → タグオブジェクトのハッシュ

  4. HEAD参照
     .git/HEAD → ref: refs/heads/main(通常)
     .git/HEAD → a0b1c2d...(detached HEAD)

  5. 特殊参照
     ORIG_HEAD → merge/rebase/reset前のHEAD
     MERGE_HEAD → マージ中の相手コミット
     FETCH_HEAD → 最後のfetchの結果

  参照の相対指定:
  HEAD~1     → HEADの1つ前の親(= HEAD~)
  HEAD~2     → HEADの2つ前の親
  HEAD^1     → HEADの最初の親(通常コミットではHEAD~と同じ)
  HEAD^2     → HEADの2番目の親(マージコミットの場合のみ意味がある)

  図で理解する:
  C1 ← C2 ← C3 ← M(マージコミット、親はC3とC5)
                 ↖
                  C4 ← C5

  M~1 = C3     (最初の親を辿る)
  M~2 = C2     (最初の親をさらに辿る)
  M^1 = C3     (最初の親)
  M^2 = C5     (2番目の親 = マージ元ブランチ)

1.4 ステージングエリア(インデックス)

Gitの3つの状態:

  Working Directory    Staging Area (Index)    Repository
編集中のファイルコミット予定の変更確定した履歴
file.py───→file.py───→commit abc
(modified)add(staged)commit
↑                                          │
        └──────────────────────────────────────────┘
                        checkout / restore

  なぜステージングエリアがあるのか:
  1. コミットの粒度を制御できる
     - 1つのファイルの一部だけをコミット可能(git add -p)
     - 複数の変更を論理的なコミットに分割

  2. コミット前のレビューができる
     - git diff --staged で確定予定の変更を確認
     - 誤った変更を含まないことを保証

  3. マージコンフリクト解決の作業スペース
     - コンフリクトをステージングで解決してからコミット
# ステージングの実践的な使い方
 
# ファイル全体をステージング
git add file.py
 
# ハンク(変更の塊)単位で対話的にステージング
git add -p file.py
# y: このハンクをステージング
# n: このハンクをスキップ
# s: ハンクをさらに分割
# e: ハンクを手動編集
 
# ステージング内容の確認
git diff --staged     # ステージングされた変更
git diff              # ステージングされていない変更
git diff HEAD         # 全ての変更(ステージング + 未ステージング)
 
# ステージングの取り消し
git restore --staged file.py  # ファイルをアンステージ(変更は保持)
git restore file.py           # ファイルの変更自体を取り消し(注意!)

2. ブランチ戦略

2.1 主要なブランチ戦略

主要なブランチ戦略:

  1. GitHub Flow(シンプル):
     main ──●──●──●──●──●──●──
                ↖     ↗
     feature    ●──●──●

     → mainは常にデプロイ可能
     → featureブランチからPRを作成
     → マージ後にデプロイ

  2. Git Flow(厳格):
     main    ──●────────────●──
     develop ──●──●──●──●──●──
                ↖  ↗     ↖  ↗
     feature    ●──●      ●──●
     release              ●──●──●

     → 開発用(develop), 安定版(main), リリース用(release)
     → 大規模プロジェクト向け

  3. Trunk-Based Development(モダン):
     main ──●──●──●──●──●──●──●──
               ↖↗  ↖↗
     short     ●    ●    ← 短命ブランチ(1日以内)

     → mainに頻繁にマージ(1日数回)
     → フィーチャーフラグで未完成機能を隠蔽
     → Google, Facebook が採用

2.2 各戦略の詳細比較

ブランチ戦略の比較表:
特性GitHub FlowGit FlowTrunk-Based
ブランチ数少ない多い最小限
複雑さ低い高い低い
リリース頻度高い低い最も高い
CI/CD適性高い中程度最も高い
チームサイズ小〜中小〜大
学習コスト低い高い低い
コンフリクト中程度多い少ない
ロールバック容易容易フラグ切替
適用環境Web/SaaSパッケージWeb/SaaS
代表的採用企業GitHub大企業Google
選択の指針:
  - Webアプリ・SaaS → GitHub Flow or Trunk-Based
  - モバイルアプリ(定期リリース)→ Git Flow
  - CI/CDを完全に構築済み → Trunk-Based
  - チームがGitに不慣れ → GitHub Flow(最もシンプル)
  - 複数バージョンの同時サポート → Git Flow

2.3 GitHub Flow の実践

# --- GitHub Flow のワークフロー ---
 
# 1. mainブランチから新しいブランチを作成
git switch main
git pull origin main
git switch -c feature/add-user-auth
 
# 2. 開発とコミット
# ... コードを編集 ...
git add src/auth.py tests/test_auth.py
git commit -m "feat: ログイン認証機能を実装"
 
git add src/middleware.py
git commit -m "feat: 認証ミドルウェアを追加"
 
git add tests/test_middleware.py
git commit -m "test: 認証ミドルウェアのテストを追加"
 
# 3. リモートにプッシュ
git push -u origin feature/add-user-auth
 
# 4. Pull Request を作成
gh pr create --title "feat: ユーザー認証機能を追加" --body "
## 概要
ログイン認証とミドルウェアを実装しました。
 
## 変更内容
- JWT ベースの認証
- 認証ミドルウェア
- テスト
 
## テスト方法
\`\`\`bash
pytest tests/test_auth.py tests/test_middleware.py
\`\`\`
"
 
# 5. レビュー後にマージ
# (GitHub UI または CLI で実行)
gh pr merge --squash
 
# 6. ローカルの片付け
git switch main
git pull origin main
git branch -d feature/add-user-auth

2.4 Trunk-Based Development の実践

# --- Trunk-Based Development のワークフロー ---
 
# 1. 短命ブランチを作成(1日以内にマージ予定)
git switch main
git pull origin main
git switch -c short-lived/add-button
 
# 2. 小さな変更をコミット
git add src/components/Button.tsx
git commit -m "feat: 新しいボタンコンポーネントを追加(フラグ付き)"
 
# 3. フィーチャーフラグで未完成機能を隠蔽
# config/features.py
# FEATURE_FLAGS = {
#     "new_button": False,  # 本番ではオフ
# }
 
# 4. すぐにマージ
git push -u origin short-lived/add-button
gh pr create --title "feat: ボタンコンポーネント追加" --body "フラグ: new_button"
gh pr merge --squash
 
# 5. mainを最新にして次の作業へ
git switch main
git pull origin main
 
# フィーチャーフラグの段階的ロールアウト:
# 1. 開発環境: フラグON → テスト
# 2. ステージング: フラグON → QA
# 3. 本番: カナリアリリース(1%のユーザーにON)
# 4. 段階的にONの割合を増加(10% → 50% → 100%)
# 5. 全ユーザーにON → フラグのコードを削除

3. コミットメッセージ

3.1 Conventional Commits

Conventional Commits 仕様:

  フォーマット:
  <type>(<scope>): <description>

  <body>

  <footer>

  type の種類:
type説明
feat新機能ログイン追加
fixバグ修正NPE修正
docsドキュメントREADME更新
styleコードスタイルフォーマット
refactorリファクタリング関数分割
perfパフォーマンス改善クエリ最適化
testテストテスト追加
buildビルドシステムwebpack設定
ciCI設定GitHub Actions
choreその他の雑務依存関係更新
revertコミットの取り消し前回の変更戻し
scope(任意): 変更の影響範囲
  → auth, api, ui, db, config 等

  BREAKING CHANGE の明示:
  → type の後に ! を付ける: feat!: ...
  → フッターに BREAKING CHANGE: ... を記載

3.2 良いコミットメッセージの書き方

# --- 良いコミットメッセージの例 ---
 
# ✅ 短い1行のメッセージ(シンプルな変更向け)
git commit -m "fix: ユーザー登録時のメールバリデーションエラーを修正"
 
# ✅ 本文付きのメッセージ(複雑な変更向け)
git commit -m "$(cat <<'EOF'
feat(auth): JWT ベースの認証機能を実装
 
パスワード認証に加え、JWTトークンによる認証を追加した。
トークンの有効期限は24時間で、リフレッシュトークンによる
自動更新をサポートする。
 
- アクセストークンの発行と検証
- リフレッシュトークンによるローテーション
- トークン無効化のためのブラックリスト
 
Closes #123
EOF
)"
 
# --- 悪いコミットメッセージの例 ---
# ❌ 何をしたか分からない
git commit -m "fix"
git commit -m "update"
git commit -m "作業中"
git commit -m "WIP"
git commit -m "misc changes"
 
# ❌ 大きすぎるコミット
git commit -m "認証機能追加、バグ修正、UIリファクタリング、テスト追加"
# → 複数のコミットに分割すべき
 
# ❌ 実装詳細だけで意図が分からない
git commit -m "if文を追加"
git commit -m "変数名をxからuserIdに変更"

3.3 コミットの粒度

適切なコミット粒度:

  原則: 1コミット = 1つの論理的な変更

  良い粒度の例:
  1. "feat: ユーザー登録APIを実装"
  2. "test: ユーザー登録APIのテストを追加"
  3. "fix: メールアドレスのバリデーションを修正"
  4. "refactor: UserServiceをリポジトリパターンに変更"

  悪い粒度の例:
  ❌ 粒度が細かすぎる:
  1. "関数のシグネチャを定義"
  2. "関数の本体を実装"
  3. "テストを1つ追加"
  4. "テストをもう1つ追加"

  ❌ 粒度が粗すぎる:
  1. "ユーザー管理機能一式を実装(認証、CRUD、API、テスト、ドキュメント)"

  コミットの分割テクニック:

  1. 変更を分けてステージング
     git add -p            # ハンク単位で選択
     git add src/auth.py   # ファイル単位で選択

  2. 作業後に分割
     git reset HEAD~1      # 最後のコミットを取り消し(変更は保持)
     git add -p            # 改めてハンク単位でコミット

  3. fixup/squash で整理
     git commit --fixup HEAD~2   # 2つ前のコミットの修正として
     git rebase -i HEAD~5        # 対話的リベースで整理
     # fixup を pick の後に配置して統合

4. マージとリベース

4.1 マージの種類

マージの3つの方法:

  1. Fast-Forward マージ
     Before:
     main    A ← B ← C
     feature           ↖ D ← E

     After (git merge feature):
     main    A ← B ← C ← D ← E

     → mainが遅れている場合に自動的に適用
     → マージコミットが作られない
     → 履歴が直線的

  2. 3-Way マージ(通常のマージ)
     Before:
     main    A ← B ← C ← F
     feature           ↖ D ← E

     After (git merge feature):
     main    A ← B ← C ← F ← M
                       ↖ D ← E ↗
     → M がマージコミット(2つの親を持つ)
     → 分岐の履歴が残る

  3. Squash マージ
     Before:
     main    A ← B ← C
     feature           ↖ D ← E ← F

     After (git merge --squash feature && git commit):
     main    A ← B ← C ← S
     → S は D+E+F を1つにまとめたコミット
     → 機能ブランチの細かい履歴を残さない
     → PRのマージでよく使われる

4.2 リベースの仕組み

リベース:

  Before:
  main    A ← B ← C ← D
  feature       ↖ E ← F ← G

  git switch feature
  git rebase main

  After:
  main    A ← B ← C ← D
  feature                ↖ E' ← F' ← G'

  → E, F, G を D の後に「貼り直す」
  → E', F', G' は新しいコミット(ハッシュが変わる)
  → 履歴が直線的になる

  リベースの利点:
  - 履歴がきれい(分岐がない直線)
  - git log が読みやすい
  - bisect がやりやすい

  リベースの注意点:
  - 公開済みのコミットをリベースしない!
    (他の人が参照しているコミットが消える)
  - プッシュ済みブランチのリベース後は force push が必要
    git push --force-with-lease origin feature
    (--force-with-lease は安全な force push)

4.3 マージ vs リベースの使い分け

マージとリベースの使い分け:

  マージを使う場合:
  - mainブランチへの統合
  - 共有ブランチの統合
  - 履歴を正確に残したい場合
  - マージの記録(いつ、何を統合したか)を残したい場合

  リベースを使う場合:
  - 個人のfeatureブランチをmainの最新に追従させる
  - コミット履歴をきれいに整理したい場合
  - PRマージ前のブランチ整理

  推奨ワークフロー:
  1. feature ブランチで開発
  2. main の変更を取り込む: git rebase main
  3. PR をレビュー
  4. main にマージ: squash merge(GitHub UI)

  ゴールデンルール:
  「公開済みの履歴をリベースしない」
  → 自分だけのブランチ: リベースOK
  → 共有ブランチ: マージを使う

4.4 対話的リベース

# --- 対話的リベース(コミット履歴の整理) ---
 
# 最新5コミットを整理
git rebase -i HEAD~5
 
# エディタが開く:
# pick a1b2c3d feat: ユーザーモデルを追加
# pick d4e5f6g feat: ユーザーAPIを実装
# pick 7a8b9c0 fix: typo修正
# pick 1d2e3f4 feat: バリデーション追加
# pick 5a6b7c8 fix: バリデーションのバグ修正
 
# 以下のように編集:
# pick a1b2c3d feat: ユーザーモデルを追加
# pick d4e5f6g feat: ユーザーAPIを実装
# fixup 7a8b9c0 fix: typo修正                 ← 上のコミットに統合
# pick 1d2e3f4 feat: バリデーション追加
# fixup 5a6b7c8 fix: バリデーションのバグ修正   ← 上のコミットに統合
 
# リベースコマンド:
# pick   = そのまま使う
# reword = コミットメッセージを変更
# edit   = コミットの内容を編集
# squash = 上のコミットに統合(メッセージも統合)
# fixup  = 上のコミットに統合(メッセージは捨てる)
# drop   = コミットを削除
 
# コミットの順序を入れ替えることも可能(行を移動するだけ)

5. コンフリクト解決

5.1 コンフリクトの発生原因

コンフリクトが発生するケース:

  1. 同じ行の変更
     main:    line = "Hello"  → line = "Hello, World!"
     feature: line = "Hello"  → line = "Hi there!"

  2. 隣接行の変更(場合による)
     一方がその行を削除し、他方が編集

  3. ファイルの削除と変更
     main:    file.py を削除
     feature: file.py を編集

  4. ファイルのリネーム
     main:    old.py → new.py
     feature: old.py を編集

  コンフリクトが発生しないケース:
  - 異なるファイルの変更
  - 同じファイルの異なる部分の変更
  - 一方がファイルを追加(既存ファイルと衝突しない)

5.2 コンフリクト解決の手順

# --- コンフリクト解決の手順 ---
 
# 1. マージ(またはリベース)を実行
git merge feature
# Auto-merging src/user.py
# CONFLICT (content): Merge conflict in src/user.py
# Automatic merge failed; fix conflicts and then commit the result.
 
# 2. コンフリクトの状態を確認
git status
# Unmerged paths:
#   both modified:   src/user.py
 
# 3. コンフリクトマーカーを確認
# ファイル内のコンフリクト表示:
# <<<<<<< HEAD
# name = "Hello, World!"
# =======
# name = "Hi there!"
# >>>>>>> feature
 
# 4. 手動で解決
# マーカーを削除し、正しい内容に編集:
# name = "Hello, World!"
 
# 5. 解決をステージング
git add src/user.py
 
# 6. マージコミットを作成
git commit  # マージの場合はメッセージが自動生成される
 
# --- リベース中のコンフリクト解決 ---
git rebase main
# CONFLICT in src/user.py
 
# 解決後:
git add src/user.py
git rebase --continue  # 次のコミットの適用に進む
 
# リベースを中断して元に戻す:
git rebase --abort

5.3 コンフリクトを減らす工夫

コンフリクトを最小限にする方法:

  1. 小さいPR を心がける
     - 変更ファイル数を少なく
     - 変更行数を少なく(目安: 200-400行以下)
     - PR のマージを早めに行う

  2. main を頻繁に取り込む
     git switch feature
     git rebase main  # 毎日実行

  3. ファイル構造を適切に設計
     - 1ファイルに多くのコードを詰め込まない
     - 関心の分離を意識する

  4. チーム内のコミュニケーション
     - 同じファイルを編集する場合は事前に共有
     - ペアプログラミングの活用

  5. フォーマッターの統一
     - .editorconfig で設定を共有
     - Prettier, Black 等を CI で強制
     - 自動フォーマットによる無意味な差分を排除

  6. ロックファイルのコンフリクト対策
     # .gitattributes でマージ戦略を指定
     package-lock.json merge=ours
     yarn.lock merge=ours

6. 実務のGitコマンド

6.1 日常コマンド

# --- 基本操作 ---
git status                  # 状態確認
git add -p                  # 対話的にステージング
git commit -m "msg"         # コミット
git push origin branch      # プッシュ
git pull --rebase           # プル(リベースマージ)
 
# --- ブランチ操作 ---
git switch -c feature       # ブランチ作成+切替
git switch main             # mainに切替
git branch -d feature       # マージ済みブランチを削除
git branch -D feature       # 未マージブランチを強制削除
 
# --- 履歴の確認 ---
git log --oneline --graph   # グラフ表示
git log --oneline -20       # 直近20件
git log --since="2024-01-01" --until="2024-01-31"  # 期間指定
git log --author="Alice"    # 作者で絞り込み
git log -p -- path/to/file  # ファイルの変更履歴を差分付きで
git blame file.py           # 各行の最終変更者
 
# --- 差分の確認 ---
git diff                    # ワーキングツリーの変更
git diff --staged           # ステージングされた変更
git diff main..feature      # ブランチ間の差分
git diff HEAD~3..HEAD       # 直近3コミットの差分
git diff --stat             # 変更の統計情報

6.2 便利なコマンド

# --- stash(一時退避)---
git stash                   # 変更を退避
git stash push -m "WIP: ログイン機能"  # メッセージ付き退避
git stash list              # 退避リスト
git stash pop               # 最新の退避を復元して削除
git stash apply stash@{1}   # 特定の退避を復元(削除しない)
git stash drop stash@{0}    # 特定の退避を削除
 
# --- cherry-pick(特定のコミットを適用)---
git cherry-pick abc1234     # 特定のコミットを現在のブランチに適用
git cherry-pick abc1234..def5678  # 範囲指定
git cherry-pick --no-commit abc1234  # コミットせずに変更だけ適用
 
# --- 特定のファイルを別ブランチから取得 ---
git checkout main -- path/to/file.py  # mainのファイルを取得
git restore --source main -- path/to/file.py  # 同上(新しい書式)
 
# --- コミットの修正 ---
git commit --amend          # 直前のコミットを修正(メッセージ変更)
git commit --amend --no-edit  # メッセージを変えずにファイルを追加
 
# --- タグ ---
git tag v1.0.0              # 軽量タグ
git tag -a v1.0.0 -m "Release 1.0.0"  # 注釈付きタグ
git push origin v1.0.0      # タグをプッシュ
git push origin --tags       # 全タグをプッシュ

6.3 トラブルシューティング

# --- reflog(HEADの移動履歴)---
git reflog
# abc1234 HEAD@{0}: commit: feat: 新機能追加
# def5678 HEAD@{1}: rebase finished: ...
# 7a8b9c0 HEAD@{2}: rebase: starting
 
# reflog を使った復旧
git reset --hard HEAD@{2}   # 2操作前の状態に戻る
 
# --- bisect(バグ導入コミットの特定)---
git bisect start
git bisect bad              # 現在のコミットはバグあり
git bisect good v1.0.0      # v1.0.0にはバグなし
# → Gitが中間のコミットをcheckout
# テストして good/bad を判定
git bisect good  # or  git bisect bad
# → 二分探索で絞り込み
git bisect reset            # 完了、元のブランチに戻る
 
# 自動化(テストスクリプトで)
git bisect start HEAD v1.0.0
git bisect run python -m pytest tests/test_bug.py
 
# --- 間違ったコミットの取り消し ---
# 方法1: revert(新しいコミットで取り消し)= 安全
git revert abc1234
git revert HEAD~3..HEAD     # 直近3コミットを取り消し
 
# 方法2: reset(履歴を巻き戻し)= 注意が必要
git reset --soft HEAD~1     # コミットを取消(変更はステージに残る)
git reset --mixed HEAD~1    # コミットを取消(変更はワーキングツリーに残る)
git reset --hard HEAD~1     # コミットを取消(変更も全て削除!)
 
# --- 消してしまったブランチの復旧 ---
git reflog | grep "feature/important"
# abc1234 HEAD@{5}: checkout: moving from feature/important to main
git branch feature/important abc1234  # ブランチを復活
 
# --- 大きなファイルの誤コミットの修正 ---
# 履歴から完全に削除(注意: 履歴を書き換える)
git filter-branch --force --tree-filter \
  'rm -f path/to/large-file.zip' HEAD
 
# より新しいツール: git-filter-repo
pip install git-filter-repo
git filter-repo --path path/to/large-file.zip --invert-paths

6.4 エイリアス設定

# --- 便利なGitエイリアス ---
git config --global alias.st "status"
git config --global alias.co "checkout"
git config --global alias.sw "switch"
git config --global alias.br "branch"
git config --global alias.ci "commit"
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.last "log -1 HEAD --format='%H %s'"
git config --global alias.unstage "restore --staged"
git config --global alias.undo "reset --soft HEAD~1"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.wip "commit -am 'WIP'"
git config --global alias.branches "branch -a -v"
git config --global alias.tags "tag -l -n1"
git config --global alias.stashes "stash list"
git config --global alias.cleanup "!git branch --merged | grep -v '\\*\\|main\\|master\\|develop' | xargs -n 1 git branch -d"
 
# 使用例
git st           # git status
git lg           # きれいなグラフ表示
git undo         # 直前のコミットを取り消し
git cleanup      # マージ済みブランチを一括削除

7. Git Hooks

7.1 Git Hooks の種類

Git Hooksの種類:

  クライアントサイドフック(ローカル):
フック名タイミング
pre-commitコミット前
prepare-commit-msgコミットメッセージ編集前
commit-msgコミットメッセージ確定後
post-commitコミット後
pre-pushプッシュ前
pre-rebaseリベース前
post-checkoutチェックアウト後
post-mergeマージ後
サーバーサイドフック:
フック名タイミング
pre-receiveプッシュ受信前
update各ブランチ更新前
post-receiveプッシュ受信後

7.2 実用的な Git Hooks の例

#!/bin/bash
# .git/hooks/pre-commit(または husky で管理)
 
# --- Lintチェック ---
echo "Running lint..."
npm run lint
if [ $? -ne 0 ]; then
    echo "❌ Lint errors found. Please fix before committing."
    exit 1
fi
 
# --- テスト実行 ---
echo "Running tests..."
npm run test -- --bail
if [ $? -ne 0 ]; then
    echo "❌ Tests failed. Please fix before committing."
    exit 1
fi
 
# --- 機密情報の検出 ---
echo "Checking for secrets..."
PATTERNS="(password|secret|api_key|token)\s*=\s*['\"][^'\"]+['\"]"
if git diff --cached --name-only | xargs grep -lE "$PATTERNS" 2>/dev/null; then
    echo "❌ Potential secrets detected. Please review."
    exit 1
fi
 
# --- 大きなファイルの検出 ---
MAX_SIZE=5242880  # 5MB
for file in $(git diff --cached --name-only); do
    if [ -f "$file" ]; then
        size=$(wc -c < "$file")
        if [ "$size" -gt "$MAX_SIZE" ]; then
            echo "❌ File $file exceeds 5MB. Use Git LFS instead."
            exit 1
        fi
    fi
done
 
echo "✅ All checks passed."
exit 0
#!/bin/bash
# .git/hooks/commit-msg
# Conventional Commits のフォーマットを強制
 
commit_msg=$(cat "$1")
pattern="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .{1,72}"
 
if ! echo "$commit_msg" | head -1 | grep -qE "$pattern"; then
    echo "❌ Invalid commit message format."
    echo ""
    echo "Expected format: <type>(<scope>): <description>"
    echo "  type: feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
    echo "  scope: optional, e.g., (auth), (api)"
    echo "  description: max 72 characters"
    echo ""
    echo "Example: feat(auth): ログイン認証を実装"
    exit 1
fi
 
exit 0

7.3 husky + lint-staged による自動化

// package.json
{
  "scripts": {
    "prepare": "husky install"
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{css,scss}": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.{json,md}": [
      "prettier --write"
    ]
  }
}
# husky のセットアップ
npm install --save-dev husky lint-staged
npx husky install
 
# pre-commit フック
npx husky add .husky/pre-commit "npx lint-staged"
 
# commit-msg フック(Conventional Commits チェック)
npm install --save-dev @commitlint/cli @commitlint/config-conventional
npx husky add .husky/commit-msg 'npx commitlint --edit "$1"'
// commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2, 'always',
      ['feat', 'fix', 'docs', 'style', 'refactor', 'perf',
       'test', 'build', 'ci', 'chore', 'revert']
    ],
    'subject-max-length': [2, 'always', 72],
    'body-max-line-length': [2, 'always', 100],
  },
};

8. CI/CDとの連携

8.1 GitHub Actions の基本

# .github/workflows/ci.yml
name: CI
 
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
 
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
 
  test:
    runs-on: ubuntu-latest
    needs: lint
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm run test -- --coverage
      - uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.node-version }}
          path: coverage/
 
  build:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/
 
  deploy:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: build
          path: dist/
      - run: echo "Deploying to production..."
      # 実際のデプロイコマンド

8.2 Pull Requestの自動化

# .github/workflows/pr-checks.yml
name: PR Checks
 
on:
  pull_request:
    types: [opened, synchronize, reopened]
 
jobs:
  # PR のサイズチェック
  pr-size:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Check PR size
        run: |
          LINES_CHANGED=$(git diff --stat origin/${{ github.base_ref }}...HEAD | tail -1 | awk '{print $4+$6}')
          echo "Lines changed: $LINES_CHANGED"
          if [ "$LINES_CHANGED" -gt 1000 ]; then
            echo "::warning::PR is too large ($LINES_CHANGED lines). Consider splitting."
          fi
 
  # 自動レビューアサイン
  auto-assign:
    runs-on: ubuntu-latest
    steps:
      - uses: kentaro-m/auto-assign-action@v2
        with:
          configuration-path: '.github/auto-assign.yml'
 
  # ラベル自動付与
  labeler:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/labeler@v5
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

8.3 セマンティックバージョニングとリリース

セマンティックバージョニング(SemVer):
  MAJOR.MINOR.PATCH

  MAJOR: 互換性のない変更
  MINOR: 後方互換性のある新機能
  PATCH: 後方互換性のあるバグ修正

  例:
  1.0.0 → 1.0.1  パッチ(バグ修正)
  1.0.0 → 1.1.0  マイナー(新機能追加)
  1.0.0 → 2.0.0  メジャー(破壊的変更)

  プレリリース:
  2.0.0-alpha.1
  2.0.0-beta.1
  2.0.0-rc.1(Release Candidate)

  Conventional Commits との対応:
  feat: → MINOR バージョンアップ
  fix:  → PATCH バージョンアップ
  feat!: または BREAKING CHANGE: → MAJOR バージョンアップ
# semantic-release による自動リリース
# Conventional Commits からバージョンを自動決定
 
# インストール
npm install --save-dev semantic-release @semantic-release/git @semantic-release/changelog
 
# .releaserc.json
# {
#   "branches": ["main"],
#   "plugins": [
#     "@semantic-release/commit-analyzer",
#     "@semantic-release/release-notes-generator",
#     "@semantic-release/changelog",
#     "@semantic-release/npm",
#     "@semantic-release/github",
#     ["@semantic-release/git", {
#       "assets": ["CHANGELOG.md", "package.json"],
#       "message": "chore(release): ${nextRelease.version}"
#     }]
#   ]
# }

9. 大規模リポジトリの運用

9.1 モノレポ vs マルチレポ

モノレポ(Monorepo):
  1つのリポジトリに全プロジェクト
monorepo/
├── packages/
├── web/ (フロントエンド)
├── api/ (バックエンド)
├── shared/ (共通ライブラリ)
└── mobile/ (モバイルアプリ)
├── tools/
├── package.json
└── turbo.json (or nx.json)
利点:
  - コード共有が容易
  - 原子的な変更(APIとフロントを同時に変更)
  - 統一されたCI/CD
  - 依存関係の一元管理

  欠点:
  - リポジトリが巨大化
  - ビルド時間の増加
  - アクセス制御が難しい
  - Git操作が遅くなる可能性

  代表ツール: Turborepo, Nx, Lerna, Bazel

マルチレポ(Multirepo):
  プロジェクトごとに別リポジトリ

  利点:
  - リポジトリが軽量
  - 独立したCI/CD
  - 細かいアクセス制御
  - チームの自律性

  欠点:
  - コード共有が困難
  - 横断的な変更が面倒
  - 依存関係の管理が複雑
  - バージョンの不整合

9.2 大きなファイルの管理

# --- Git LFS(Large File Storage)---
 
# インストール
git lfs install
 
# 追跡するファイルパターンを指定
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "*.mp4"
git lfs track "assets/images/*.png"
 
# .gitattributes が自動生成される
# *.psd filter=lfs diff=lfs merge=lfs -text
# *.zip filter=lfs diff=lfs merge=lfs -text
 
# 通常通りadd/commit/push
git add .gitattributes
git add large-file.psd
git commit -m "feat: デザインファイルを追加"
git push origin main
 
# LFS の状態確認
git lfs ls-files     # LFS管理ファイル一覧
git lfs status       # LFS の状態

9.3 .gitignore のベストプラクティス

# --- .gitignore の推奨設定 ---
 
# --- OS ---
.DS_Store
Thumbs.db
*.swp
*~
 
# --- エディタ/IDE ---
.vscode/settings.json
.idea/
*.sublime-workspace
*.code-workspace
 
# --- 言語/フレームワーク ---
# Node.js
node_modules/
npm-debug.log*
yarn-error.log*
.pnpm-debug.log*
 
# Python
__pycache__/
*.py[cod]
*.pyo
.venv/
venv/
*.egg-info/
dist/
build/
 
# Java
*.class
target/
*.jar
*.war
 
# Go
/vendor/
 
# --- ビルド成果物 ---
dist/
build/
out/
.next/
.nuxt/
 
# --- 環境変数・機密情報 ---
.env
.env.local
.env.production
*.pem
*.key
credentials.json
 
# --- テスト/カバレッジ ---
coverage/
.nyc_output/
*.lcov
htmlcov/
 
# --- ログ ---
*.log
logs/
 
# --- データベース ---
*.sqlite3
*.db
 
# グローバル .gitignore(全リポジトリ共通)
git config --global core.excludesfile ~/.gitignore_global

10. セキュリティ

10.1 機密情報の管理

Gitリポジトリでの機密情報管理:

  絶対にコミットしてはいけないもの:
  - パスワード、APIキー
  - 秘密鍵(.pem, .key)
  - .env ファイル(本番環境の値)
  - credentials.json
  - データベース接続文字列

  対策:
  1. .gitignore に追加
  2. .env.example をコミット(値は空またはダミー)
  3. git-secrets で事前検出
  4. 万が一コミットした場合は即座にキーをローテーション

  git-secrets のセットアップ:
# git-secrets のインストールと設定
brew install git-secrets  # macOS
 
# リポジトリに設定
cd my-project
git secrets --install
git secrets --register-aws  # AWSキーパターンを登録
 
# カスタムパターンの追加
git secrets --add 'password\s*=\s*["\047][^"\047]+["\047]'
git secrets --add 'PRIVATE[_-]?KEY'
 
# コミット前に自動チェック(pre-commit hook に追加される)
git secrets --scan         # リポジトリ全体をスキャン
git secrets --scan-history # 全履歴をスキャン

10.2 GPG署名

# --- コミット署名(GPG)---
 
# GPGキーの生成
gpg --full-generate-key
 
# キーIDの確認
gpg --list-secret-keys --keyid-format=long
# sec   rsa4096/ABC1234567890DEF 2024-01-01 [SC]
 
# Gitに設定
git config --global user.signingkey ABC1234567890DEF
git config --global commit.gpgsign true  # 全コミットに署名
 
# 署名付きコミット
git commit -S -m "feat: 署名付きコミット"
 
# 署名の検証
git log --show-signature
# gpg: Good signature from "Alice <alice@example.com>"
 
# GitHubに公開鍵を登録
gpg --armor --export ABC1234567890DEF
# → GitHubの Settings → SSH and GPG keys に追加

11. Gitの高度なテクニック

11.1 worktree(複数作業ディレクトリ)

# --- git worktree ---
# 1つのリポジトリで複数のブランチを同時にチェックアウト
 
# 新しいworktreeを作成
git worktree add ../project-hotfix hotfix/critical-bug
git worktree add ../project-review feature/new-ui
 
# worktreeの一覧
git worktree list
# /path/to/project          abc1234 [main]
# /path/to/project-hotfix   def5678 [hotfix/critical-bug]
# /path/to/project-review   7a8b9c0 [feature/new-ui]
 
# worktreeの削除
git worktree remove ../project-hotfix
 
# ユースケース:
# - 長時間のビルドを別ディレクトリで実行しつつ開発を続ける
# - コードレビュー用に別ブランチをチェックアウト
# - 緊急のhotfixを本作業を中断せずに対応

11.2 サブモジュール

# --- git submodule ---
# 外部リポジトリをサブディレクトリとして含める
 
# サブモジュールの追加
git submodule add https://github.com/example/library.git libs/library
git commit -m "feat: libraryをサブモジュールとして追加"
 
# サブモジュール付きリポジトリのクローン
git clone --recurse-submodules https://github.com/example/project.git
# または
git clone https://github.com/example/project.git
cd project
git submodule init
git submodule update
 
# サブモジュールの更新
git submodule update --remote  # リモートの最新を取得
cd libs/library
git checkout v2.0.0            # 特定のバージョンに固定
cd ../..
git add libs/library
git commit -m "chore: libraryをv2.0.0に更新"
 
# サブモジュールの注意点:
# - 複雑さが増す(クローン時に --recurse-submodules が必要)
# - CIの設定が複雑になる
# - 代替手段: npm/pip等のパッケージマネージャーを検討

11.3 パフォーマンス最適化

# --- 大規模リポジトリのパフォーマンス改善 ---
 
# シャロークローン(履歴を制限)
git clone --depth 1 https://github.com/large/repo.git
git clone --depth 100 https://github.com/large/repo.git
git clone --shallow-since="2024-01-01" https://github.com/large/repo.git
 
# 部分クローン(blobを遅延取得)
git clone --filter=blob:none https://github.com/large/repo.git
 
# スパースチェックアウト(特定のディレクトリのみ)
git clone --no-checkout https://github.com/large/repo.git
cd repo
git sparse-checkout init --cone
git sparse-checkout set packages/web packages/shared
git checkout main
# → packages/web と packages/shared のみがチェックアウトされる
 
# fsmonitor(ファイル監視デーモン)で高速化
git config core.fsmonitor true
git config core.untrackedcache true
 
# gc(ガベージコレクション)
git gc --aggressive  # リポジトリの最適化
git prune            # 不要オブジェクトの削除
 
# パフォーマンス確認
git count-objects -vH  # オブジェクト数とサイズ

12. チーム開発のベストプラクティス

12.1 CODEOWNERS

# --- .github/CODEOWNERS ---
# ファイル/ディレクトリごとにレビューアを自動アサイン
 
# デフォルトのオーナー
* @team-lead
 
# フロントエンド
/src/components/ @frontend-team
/src/pages/ @frontend-team
*.tsx @frontend-team
*.css @frontend-team
 
# バックエンド
/src/api/ @backend-team
/src/models/ @backend-team
/src/services/ @backend-team
 
# インフラ
/terraform/ @infra-team
/docker/ @infra-team
/.github/workflows/ @infra-team
Dockerfile @infra-team
 
# ドキュメント
/docs/ @tech-writers
*.md @tech-writers
 
# セキュリティ関連
/src/auth/ @security-team
/src/middleware/auth* @security-team

12.2 Pull Request テンプレート

<!-- .github/pull_request_template.md -->
 
## 概要
<!-- この PR で何を変更しましたか? -->
 
## 変更の種類
- [ ] 新機能(feat)
- [ ] バグ修正(fix)
- [ ] リファクタリング(refactor)
- [ ] ドキュメント(docs)
- [ ] テスト(test)
- [ ] その他
 
## 変更内容
<!-- 変更の詳細を記載 -->
 
## テスト方法
<!-- テスト手順を記載 -->
 
## スクリーンショット
<!-- UI変更がある場合はスクリーンショットを添付 -->
 
## チェックリスト
- [ ] テストを追加/更新した
- [ ] ドキュメントを更新した
- [ ] 破壊的変更はない
- [ ] パフォーマンスへの影響を確認した
- [ ] セキュリティへの影響を確認した
 
## 関連Issue
Closes #

12.3 ブランチ保護ルール

推奨するブランチ保護設定(main ブランチ):
設定項目推奨値
Require pull requestON
Required reviewers1-2人
Dismiss stale reviewsON
Require status checksON
Require branches up to dateON
Require conversationON
resolution
Require signed commits必要に応じて
Include administratorsON
Allow force pushesOFF
Allow deletionsOFF
必須のステータスチェック:
  - CI(lint, test, build)
  - セキュリティスキャン
  - コードカバレッジ閾値

実践演習

演習1: 基本的な実装

以下の要件を満たすコードを実装してください。

要件:

  • 入力データの検証を行うこと
  • エラーハンドリングを適切に実装すること
  • テストコードも作成すること
# 演習1: 基本実装のテンプレート
class Exercise1:
    """基本的な実装パターンの演習"""
 
    def __init__(self):
        self.data = []
 
    def validate_input(self, value):
        """入力値の検証"""
        if value is None:
            raise ValueError("入力値がNoneです")
        return True
 
    def process(self, value):
        """データ処理のメインロジック"""
        self.validate_input(value)
        self.data.append(value)
        return self.data
 
    def get_results(self):
        """処理結果の取得"""
        return {
            'count': len(self.data),
            'data': self.data
        }
 
# テスト
def test_exercise1():
    ex = Exercise1()
    assert ex.process(1) == [1]
    assert ex.process(2) == [1, 2]
    assert ex.get_results()['count'] == 2
 
    try:
        ex.process(None)
        assert False, "例外が発生するべき"
    except ValueError:
        pass
 
    print("全テスト合格!")
 
test_exercise1()

演習2: 応用パターン

基本実装を拡張して、以下の機能を追加してください。

# 演習2: 応用パターン
from typing import List, Dict, Optional
from datetime import datetime
 
class AdvancedExercise:
    """応用パターンの演習"""
 
    def __init__(self, max_size: int = 100):
        self._items: List[Dict] = []
        self._max_size = max_size
        self._created_at = datetime.now()
 
    def add(self, key: str, value: any) -> bool:
        """アイテムの追加(サイズ制限付き)"""
        if len(self._items) >= self._max_size:
            return False
        self._items.append({
            'key': key,
            'value': value,
            'timestamp': datetime.now().isoformat()
        })
        return True
 
    def find(self, key: str) -> Optional[Dict]:
        """キーによる検索"""
        for item in reversed(self._items):
            if item['key'] == key:
                return item
        return None
 
    def remove(self, key: str) -> bool:
        """キーによる削除"""
        for i, item in enumerate(self._items):
            if item['key'] == key:
                self._items.pop(i)
                return True
        return False
 
    def stats(self) -> Dict:
        """統計情報"""
        return {
            'total_items': len(self._items),
            'max_size': self._max_size,
            'usage_percent': len(self._items) / self._max_size * 100,
            'uptime': str(datetime.now() - self._created_at)
        }
 
# テスト
def test_advanced():
    ex = AdvancedExercise(max_size=3)
    assert ex.add("a", 1) == True
    assert ex.add("b", 2) == True
    assert ex.add("c", 3) == True
    assert ex.add("d", 4) == False  # サイズ制限
    assert ex.find("b")['value'] == 2
    assert ex.remove("b") == True
    assert ex.find("b") is None
    stats = ex.stats()
    assert stats['total_items'] == 2
    print("応用テスト全合格!")
 
test_advanced()

演習3: パフォーマンス最適化

以下のコードのパフォーマンスを改善してください。

# 演習3: パフォーマンス最適化
import time
from functools import lru_cache
 
# 最適化前(O(n^2))
def slow_search(data: list, target: int) -> int:
    """非効率な検索"""
    for i in range(len(data)):
        for j in range(i + 1, len(data)):
            if data[i] + data[j] == target:
                return (i, j)
    return (-1, -1)
 
# 最適化後(O(n))
def fast_search(data: list, target: int) -> tuple:
    """ハッシュマップを使った効率的な検索"""
    seen = {}
    for i, num in enumerate(data):
        complement = target - num
        if complement in seen:
            return (seen[complement], i)
        seen[num] = i
    return (-1, -1)
 
# ベンチマーク
def benchmark():
    import random
    data = list(range(5000))
    random.shuffle(data)
    target = data[100] + data[4000]
 
    start = time.time()
    result1 = slow_search(data, target)
    slow_time = time.time() - start
 
    start = time.time()
    result2 = fast_search(data, target)
    fast_time = time.time() - start
 
    print(f"非効率版: {slow_time:.4f}秒")
    print(f"効率版:   {fast_time:.6f}秒")
    print(f"高速化率: {slow_time/fast_time:.0f}倍")
 
benchmark()

ポイント:

  • アルゴリズムの計算量を意識する
  • 適切なデータ構造を選択する
  • ベンチマークで効果を測定する

トラブルシューティング

よくあるエラーと解決策

エラー 原因 解決策
初期化エラー 設定ファイルの不備 設定ファイルのパスと形式を確認
タイムアウト ネットワーク遅延/リソース不足 タイムアウト値の調整、リトライ処理の追加
メモリ不足 データ量の増大 バッチ処理の導入、ページネーションの実装
権限エラー アクセス権限の不足 実行ユーザーの権限確認、設定の見直し
データ不整合 並行処理の競合 ロック機構の導入、トランザクション管理

デバッグの手順

  1. エラーメッセージの確認: スタックトレースを読み、発生箇所を特定する
  2. 再現手順の確立: 最小限のコードでエラーを再現する
  3. 仮説の立案: 考えられる原因をリストアップする
  4. 段階的な検証: ログ出力やデバッガを使って仮説を検証する
  5. 修正と回帰テスト: 修正後、関連する箇所のテストも実行する
# デバッグ用ユーティリティ
import logging
import traceback
from functools import wraps
 
# ロガーの設定
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s'
)
logger = logging.getLogger(__name__)
 
def debug_decorator(func):
    """関数の入出力をログ出力するデコレータ"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        logger.debug(f"呼び出し: {func.__name__}(args={args}, kwargs={kwargs})")
        try:
            result = func(*args, **kwargs)
            logger.debug(f"戻り値: {func.__name__} -> {result}")
            return result
        except Exception as e:
            logger.error(f"例外発生: {func.__name__}: {e}")
            logger.error(traceback.format_exc())
            raise
    return wrapper
 
@debug_decorator
def process_data(items):
    """データ処理(デバッグ対象)"""
    if not items:
        raise ValueError("空のデータ")
    return [item * 2 for item in items]

パフォーマンス問題の診断

パフォーマンス問題が発生した場合の診断手順:

  1. ボトルネックの特定: プロファイリングツールで計測
  2. メモリ使用量の確認: メモリリークの有無をチェック
  3. I/O待ちの確認: ディスクやネットワークI/Oの状況を確認
  4. 同時接続数の確認: コネクションプールの状態を確認
問題の種類 診断ツール 対策
CPU負荷 cProfile, py-spy アルゴリズム改善、並列化
メモリリーク tracemalloc, objgraph 参照の適切な解放
I/Oボトルネック strace, iostat 非同期I/O、キャッシュ
DB遅延 EXPLAIN, slow query log インデックス、クエリ最適化

FAQ

Q1: このトピックを学ぶ上で最も重要なポイントは何ですか?

実践的な経験を積むことが最も重要です。理論だけでなく、実際にコードを書いて動作を確認することで理解が深まります。

Q2: 初心者がよく陥る間違いは何ですか?

基礎を飛ばして応用に進むことです。このガイドで説明している基本概念をしっかり理解してから、次のステップに進むことをお勧めします。

Q3: 実務ではどのように活用されていますか?

このトピックの知識は、日常的な開発業務で頻繁に活用されます。特にコードレビューやアーキテクチャ設計の際に重要になります。


まとめ

概念 ポイント
Gitの内部 DAG + コンテンツアドレス。改ざん不可能
ブランチ ただのポインタ。軽量に作成・削除
戦略 GitHub Flow(シンプル), Trunk-Based(モダン)
コミット Conventional Commits、1コミット1論理変更
マージ vs リベース 共有ブランチはマージ、個人ブランチはリベース
コンフリクト 小さいPR + 頻繁なリベースで最小化
Hooks pre-commit でリント・テスト・機密情報チェック
CI/CD GitHub Actions で自動化
セキュリティ 機密情報は .gitignore + git-secrets
必須スキル rebase, stash, bisect, reflog

次に読むべきガイド


参考文献

  1. Chacon, S. & Straub, B. "Pro Git." 2nd Edition, Apress, 2014.
  2. Driessen, V. "A Successful Git Branching Model." 2010.
  3. Conventional Commits Specification. https://www.conventionalcommits.org/
  4. GitHub Flow Guide. https://docs.github.com/en/get-started/quickstart/github-flow
  5. Atlassian Git Tutorials. https://www.atlassian.com/git/tutorials
  6. Trunk Based Development. https://trunkbaseddevelopment.com/
  7. Semantic Versioning. https://semver.org/