概要
バージョン管理(Version Control)とは、ソースコードや設定ファイルなどの変更履歴を記録・管理するシステムです。誰が・いつ・何を変更したかを追跡し、過去のバージョンへの復帰、複数人での並行開発(ブランチ)、変更内容の比較(diff)などを可能にします。
現代の組み込み開発では、Git(Linus Torvaldsが2005年に開発)が事実上の標準バージョン管理システムとなっています。GitHubやGitLabなどのホスティングサービスと組み合わせることで、チームでの協調開発、コードレビュー(Pull Request/Merge Request)、CI/CDパイプラインの自動化が実現します。
組み込み開発では、ファームウェアのバイナリ管理、リンカスクリプト・デバイスツリーなどのテキスト管理、ドキュメント・テスト結果の管理にも活用されます。
歴史・背景
1970〜80年代:SCCS(Source Code Control System、1972年)やRCS(Revision Control System、1982年)など初期のファイル単位バージョン管理システムが登場しました。
1990年代:CVS(Concurrent Versions System)が普及し、複数人での並行開発が容易になりました。しかしCVSのブランチ・マージの扱いにくさから、SVN(Subversion、2000年)が登場しCVSを置き換えました。
2005年:Linus TorvaldsがLinuxカーネル開発のためにGitを開発。分散型バージョン管理(各ユーザーがリポジトリの完全なコピーを持つ)により高速性・柔軟性を実現しました。
2008年:GitHubがサービス開始。Pull Requestベースのコードレビューフローを普及させ、オープンソース開発のスタイルを変えました。
2010年代:GitHubのフォーク・Pull Requestモデルがオープンソースだけでなく企業内開発にも普及。GitLabがセルフホスト型CI/CDを強化し、組み込み開発での採用が広がりました。
2020年代:GitHub Actionsの登場(2019年)により、リポジトリとCI/CDの統合が極めて容易になりました。組み込みファームウェアのビルド・テスト・リリースを全てGit/GitHubで管理するプラクティスが普及しています。
技術仕様
Git の基本概念
ワーキングディレクトリ(作業ツリー)
↓ git add
ステージングエリア(インデックス)
↓ git commit
ローカルリポジトリ(.git/)
↓ git push
リモートリポジトリ(GitHub/GitLab等)
組み込み開発での典型的なリポジトリ構成
my-firmware/
├── .git/
├── .github/
│ └── workflows/
│ ├── build.yml # ビルド自動化
│ └── test.yml # テスト自動化
├── src/
│ ├── main.c
│ ├── drivers/
│ └── hal/
├── include/
├── test/ # ユニットテスト
├── docs/ # ドキュメント
├── tools/ # ビルドスクリプト
├── third_party/ # サードパーティライブラリ(gitサブモジュール)
├── CMakeLists.txt
├── linker_script.ld
├── .gitignore
└── README.md
.gitignoreの設定(組み込み開発用)
# ビルド成果物
build/
*.o
*.elf
*.bin
*.hex
*.map
*.lst
# IDEの設定ファイル(プロジェクト固有のものはコミット、ユーザー設定は除外)
.vscode/settings.json
.vscode/launch.json
*.suo
*.user
Debug/
Release/
# STM32CubeIDE 固有
.metadata/
.settings/
.cproject
RemoteSystemsTempFiles/
# Keil MDK
*.uvguix.*
*.uvoptx
*.bak
# 一時ファイル・OS固有
.DS_Store
Thumbs.db
*.swp
*~
# gcovカバレッジファイル(CIでは保持するが通常は除外)
*.gcda
*.gcno
動作原理
Gitの内部構造
コミットオブジェクトの構造:
commit abc1234
├── tree: def5678 ← そのコミット時のファイルツリー
├── parent: bcd9012 ← 前のコミット
├── author: 田中太郎 <t@example.com>
└── message: "Fix sensor timeout bug"
tree def5678
├── blob: 111aaaa src/main.c ← ファイルの内容
├── blob: 222bbbb src/sensor.c
└── tree: 333cccc include/ ← サブディレクトリ
各コミットはSHA-1/SHA-256ハッシュで識別され
内容が1bitでも違えば異なるハッシュになる
→ 改ざん検知・整合性確保
ブランチ戦略(組み込み開発向け)
Git Flow(複雑な製品向け):
main ────────────────────────────────► (リリース済み安定版)
↑
merge
|
develop ─────────────────────────────► (開発中)
↑ ↑
feature/ feature/
sensor-v2 can-protocol
Trunk-Based Development(CI/CD重視):
main ────────────────────────────────► (常にビルド可能)
↑ ↑ ↑ ↑
short-lived feature branches
(最大1〜2日で main にマージ)
組み込みでは長期サポート(LTS)版の管理も重要です:
# v1.x と v2.x を並行サポートする例
git branch release/v1.x
git branch release/v2.x
# バグ修正を両方に適用
git checkout release/v1.x
git cherry-pick abc1234 # バグ修正コミットを適用
サブモジュールの管理
組み込み開発ではサードパーティライブラリをgit submoduleで管理することが多いです:
# サブモジュールを追加
git submodule add https://github.com/FreeRTOS/FreeRTOS.git third_party/freertos
# クローン時にサブモジュールも取得
git clone --recursive https://github.com/your-org/firmware.git
# 既存クローン後にサブモジュール初期化
git submodule update --init --recursive
# サブモジュールを特定バージョンに固定
cd third_party/freertos
git checkout V10.5.1
cd ../..
git add third_party/freertos
git commit -m "freertos: Update to V10.5.1"
用途・ユースケース
ファームウェアのタグ管理とリリース
# バージョンタグの付与
git tag -a v1.2.3 -m "Release v1.2.3: Fixed I2C timeout, Added BLE support"
git push origin v1.2.3
# GitHub Releases と連携してバイナリを配布
# .github/workflows/release.yml で自動化
# タグ作成時に firmware.bin/hex を自動ビルドして添付
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install toolchain
run: sudo apt-get install -y gcc-arm-none-eabi
- name: Build firmware
run: make release
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: |
build/firmware.bin
build/firmware.hex
コードレビューとPull Request
# フィーチャーブランチを作成して作業
git checkout -b feature/add-watchdog-timer
# 変更をコミット
git add src/watchdog.c include/watchdog.h
git commit -m "Add software watchdog timer for task monitoring
- 各タスクのハートビートを1000ms間隔で監視
- タイムアウト時はシステムリセットを実行
- FreeRTOS対応
Closes #42"
# Push してPull Request作成
git push origin feature/add-watchdog-timer
# → GitHub/GitLab でPull Request作成
# → CI/CDが自動でビルド・テスト
# → レビュー後にマージ
バイナリ差分の管理(LFS)
大きなバイナリファイル(プリビルドライブラリ、テストベクタ等)はGit LFS(Large File Storage)で管理します:
# Git LFSのインストールと設定
git lfs install
git lfs track "*.bin" "*.hex" "*.a"
git add .gitattributes
# 以後 *.bin, *.hex, *.a は LFS で管理される
実装・開発のポイント
コミットメッセージの規約
組み込みプロジェクトでは変更の種類を明確にするため、Conventional Commits形式が有用です:
<type>(<scope>): <subject>
<body>
<footer>
type: feat | fix | docs | style | refactor | test | chore | perf
scope: sensor | comm | rtos | hal | bootloader など
例:
fix(i2c): Fix ACK timeout handling for slow sensors
HAL_I2C_Master_Transmit のタイムアウト値が短すぎたため、
一部の低速センサー(BMP280)でNACKが検出されていた。
タイムアウトを100msから500msに変更。
Fixes #123
Tested on: STM32F407VG with BMP280 @ 100kHz
バイナリとソースの分離
# フラッシュメモリのイメージ(バイナリ)はGit LFS
# または releases に添付し、Gitには含めない
# .gitignore でビルド成果物を除外
echo "*.bin" >> .gitignore
echo "*.elf" >> .gitignore
# 代わりにビルドスクリプトとツールチェーンバージョンをコミット
# → 再現性のあるビルド環境を保証
他技術との比較
| 比較項目 | Git | SVN(Subversion) | CVS |
|---|---|---|---|
| 分散/集中 | 分散型(ローカルに完全なコピー) | 集中型 | 集中型 |
| ブランチコスト | 非常に低い(ポインタ操作) | 高い(コピー) | 高い |
| オフライン作業 | 可能(ローカルコミット) | 不可 | 不可 |
| マージ能力 | 強力(3-way merge) | 弱い | 非常に弱い |
| バイナリ対応 | LFSで対応 | 対応 | 弱い |
| 学習コスト | 中(概念が多い) | 低 | 低 |
| CI/CDエコシステム | 非常に豊富 | 一部対応 | ほぼなし |
CI/CDとの統合において、Gitのブランチ戦略とタグ管理がビルド・テスト・デプロイフローの基盤となります。