Git は何をしますか?
Gitはモダンソフトウェアの基盤です。2025年には、スパースチェックアウトやScalar(モノレポ向け)といった機能が主流になりつつあります。
使用するタイミング
- ブランチ作成とコラボレーション: 分散チーム間での機能の分離、プルリクエスト、トランクベース開発、コードレビューの管理。
- 履歴の書き換えとクリーンアップ: コミットグラフの線形化、WIPコミットのsquash、
git rebase -iを使ったメッセージ編集をメインブランチにマージする前に行う。 - 自動バグハンティング:
git bisectを使った二分探索により、数千のリビジョンの中からリグレッションを引き起こしたコミットを特定。 - 並行ワークスペースコンテキスト:
git worktreeを使い、stashやブランチの切り替えなしに緊急ホットフィックスに取り組む。 - 大規模リポジトリのスケーリング: Git Sparse Checkout、Scalar、shallow cloneを使用した巨大モノレポのパフォーマンス最適化。
クイックスタート
# リポジトリのクローンと新しいフィーチャーブランチの作成
git clone https://github.com/myorg/project.git
cd project
# モダンなコマンドで新しいブランチを作成して切り替え
git switch -c feature/auth-flow
# ステージ、コミット、上流追跡付きでプッシュ
git add .
git commit -m "feat(auth): implement oauth2 authorization code flow"
git push -u origin feature/auth-flow
コアコンセプト
3ツリーアーキテクチャ(ワーキングツリー、インデックス、HEAD)
Gitは、単にリビジョン間の変更を追跡するのではなく、3つの異なる状態でファイルを管理します:
# 1. ワーキングツリー: エディタで変更されコミットされていないファイル
echo "export const API_URL = 'https://api.v2.internal';" >> config.ts
# 2. インデックス(ステージングエリア): 次のコミットのために準備されたコンテンツ
git add config.ts
# 3. HEAD: アクティブブランチ上の最後にコミットされたスナップショット
git diff --staged # ステージングとHEADの差分を確認
git commit -m "chore(config): update internal API endpoint"
有向非巡回グラフ(DAG)とイミュータブルなオブジェクト
Gitのすべてのコミットは、親ハッシュとブロブスナップショットのルートツリーを指すイミュータブルなノードです。
# 任意のコミットハッシュまたはHEADの背後にある生のオブジェクトを調査
git cat-file -p HEAD
# 出力:
# tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
# parent 8f3d1e1c3a628a58a98b47cf7d12a9e32049e712
# author Alice <[email protected]> 1727420400 +0000
# committer Alice <[email protected]> 1727420400 +0000
#
# feat(auth): implement oauth2 authorization code flow
モダンなブランチナビゲーション(git switch vs git restore)
モダンGitでは、過負荷になっていたgit checkoutコマンドを専用の操作に分割しました:
# ブランチ切り替え(git checkout <branch> の代わり)
git switch main
git switch -c feature/payments # 作成して切り替え
# ファイル復元(git checkout -- <file> の代わり)
git restore src/app.ts # ワーキングディレクトリの未コミット変更を破棄
git restore --staged src/app.ts # ファイルをインデックスからワーキングツリーへアンステージ
リベース vs マージ戦略
- マージ(
git merge <branch>): 2つの親を持つマージコミットで完全な履歴コンテキストを保持。長期リリースブランチの統合に最適。 - リベース(
git rebase <upstream>): トピックブランチのコミットを上流HEADの上に線形に適用し、複雑な「線路」グラフを防止。PRレビュー前にフィーチャーブランチをクリーンにするのに最適。
# フィーチャーブランチを最新のmainにクリーンにリベース
git switch feature/auth-flow
git fetch origin main
git rebase origin/main
一般的なパターン
Git Worktreesを使ったマルチブランチ開発
問題: 未コミットの作業をstashして、緊急プロダクションバグを修正するためにブランチを切り替える必要がある。
解決策: 複数のブランチを別々のディレクトリに同時にチェックアウト:
# ホットフィックスブランチ用の並行ワークツリーフォルダを作成
git worktree add ../hotfix-branch main
# 別のディレクトリでホットフィックスに取り組み、現在のワークスペースには影響を与えない
cd ../hotfix-branch
git commit -am "fix: patch critical auth vulnerability"
git push origin hotfix-branch
# 完了後、ワークツリーを削除
cd ../project
git worktree remove ../hotfix-branch
クリーンなプルリクエスト履歴のためのインタラクティブリベース
問題: フィーチャーブランチに数十の乱雑な「WIP」「fix typo」「checkpoint」コミットがある。 解決策: プルリクエストを開く前に、インタラクティブにsquashして履歴をクリーンにする。
# 最新4つのコミットをインタラクティブにリベース
git rebase -i HEAD~4
# インタラクティブエディタで:
# pick 8f3d1e1 feat(auth): add token generation
# squash 4b825dc fix typo in token payload
# squash a1c94e2 add missing import
# reword 91f7a02 feat(auth): add refresh token endpoint
Git Bisectを使った自動回帰ハンティング
問題: 500コミットのどこかでバグが混入したが、正確なコミットが不明。 解決策: 自動テスト実行スクリプトを使った二分探索を実行。
# bisectセッション開始
git bisect start
git bisect bad HEAD # 現在のHEADは壊れている
git bisect good v2.1.0 # v2.1.0は正常に動作していた
# 各bisectステップで自動的にテストスクリプトを実行
git bisect run npm test -- --runInBand
# Gitはテストスイートを壊した正確な最初のコミットで終了
git bisect reset
ベストプラクティス(2026年版)
Do(推奨事項):
git switchとgit restoreを使う: 過負荷なgit checkoutを避け、誤ったブランチ切り替えやファイル上書きを防止。--force-with-leaseでプッシュする: リモートブランチで同僚のコミットを上書きするのを防ぐ。- バックグラウンドメンテナンスを有効にする:
git maintenance startを実行して、パックファイル、コミットグラフ、フェッチパフォーマンスを最適化。 - コミットにSSH/GPG署名を行う: プロダクションパイプラインでのコミットの真正性を保証。
- Conventional Commitsを書く: 標準化されたプレフィックス(
feat:,fix:,chore:,refactor:)を使用し、セマンティックバージョニングとチェンジログを自動化。
Don't(禁止事項):
- 保護されたブランチにforce pushしない:
main、master、共有リリースブランチの履歴は決して書き換えない。 - シークレットや認証情報をコミットしない:
.gitignoreや git-secrets/trufflehogを使用する。一度コミットされると、後で削除してもパックファイルのブロブに認証情報が残る。 - 大きなバイナリファイルを直接使用しない: 大きなモデルウェイトやメディアはGit LFS(Large File Storage)やS3に保存する。
- ダーティなワーキングツリーのままマージしない: プルやリベースの前にstashまたはコミットし、偶発的なファイル競合を避ける。
トラブルシューティング
| エラー | 原因 | 解決策 |
|---|---|---|
fatal: refusing to merge unrelated histories | 共通ルートコミットなしで独立して初期化されたリポジトリからのプル。 | git pull origin main --allow-unrelated-histories を実行。 |
HEAD detached at ... | ブランチ名ではなく特定のコミットハッシュをチェックアウトした。 | 現在位置からブランチを作成: git switch -c recovery-branch。 |
Merge conflict in file.txt | 並行コミットが対立するブランチの同一行を変更した。 | 競合マーカー(<<<<<<<)を解決し、ファイルをステージ(git add)し、git commit を実行。 |