【VBA×Git】バイナリとソースの乖離を埋める。プロジェクト属性へのコミットハッシュ自動埋め込みの実装
VBAの保守現場において、「今、この`.xlsm`にはどのコードが入っているのか?」という問いは、もはや古典的な呪いである。Gitでソース管理を行っていても、最終的に配布されるバイナリファイルが最新版である保証はどこにもない。
今回は、この「バイナリとリポジトリの乖離」を断ち切るための極限手法を共有する。`Workbook_BeforeSave`イベントをフックし、Gitの現在のコミットハッシュをExcelの「カスタムドキュメントプロパティ」へ自動注入するアーキテクチャだ。
1. 概念設計:なぜカスタムプロパティなのか
Git管理下にあるVBAプロジェクトにおいて、ソースコードとバイナリの整合性をとる最も堅牢な方法は、「保存の瞬間に、バイナリ自体にメタデータを刻み込む」ことである。
`BuiltinDocumentProperties`ではなく、あえて`CustomDocumentProperties`を使用するのは、ユーザーが後からメタデータを検索・抽出する際の柔軟性を確保するためだ。これにより、CI/CDパイプラインや管理用スクリプトから、バイナリを一切開くことなくメタデータだけを吸い出し、バージョン整合性を検証することが可能になる。
2. 実装:WScript.ShellによるGitアクセスとオブジェクト管理
VBAからGitを叩く際、最も避けるべきは「重い外部ライブラリの参照設定」だ。実行環境が固定できない社内システムにおいて、参照設定はトラブルの温床となる。ここでは`WScript.Shell`を用いた遅延バインディングを採用し、メモリとランタイムの安全性を担保する。
実装コード:`ThisWorkbook`モジュール
‘ ==============================================================================
‘ Title: Project Git-Metadata Injector
‘ Author: Chief Architect
‘ Description: 保存時にGitコミットハッシュをカスタムプロパティに同期する
‘ ==============================================================================
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
On Error GoTo Cleanup
Dim commitHash As String
commitHash = GetLatestCommitHash()
If commitHash <> “” Then
UpdateCustomProperty “GitCommitHash”, commitHash
End If
Cleanup:
‘ 明示的なオブジェクト解放は不要だが、エラー発生時のハンドリングは必須
End Sub
Private Function GetLatestCommitHash() As String
Dim shell As Object
Dim exec As Object
Dim cmd As String
‘ Gitのコミットハッシュを取得。エラー時は空文字を返す
cmd = “git rev-parse –short HEAD”
Set shell = CreateObject(“WScript.Shell”)
On Error Resume Next
Set exec = shell.Exec(cmd)
If Err.Number = 0 Then
GetLatestCommitHash = Trim(exec.StdOut.ReadAll)
End If
On Error GoTo 0
Set exec = Nothing
Set shell = Nothing
End Function
Private Sub UpdateCustomProperty(propName As String, propValue As String)
Dim props As Object
Dim p As Object
Dim exists As Boolean
Set props = ThisWorkbook.CustomDocumentProperties
‘ プロパティの存在確認と更新
On Error Resume Next
Set p = props(propName)
exists = (Err.Number = 0)
On Error GoTo 0
If exists Then
props(propName).Value = propValue
Else
props.Add Name:=propName, LinkToContent:=False, Type:=4, Value:=propValue ‘ 4 = msoPropertyTypeString
End If
End Sub
3. チーフアーキテクトの視点:パフォーマンスとリスク管理
この実装を導入する際、以下の3点に注意を払う必要がある。
- 非同期処理の限界: `WScript.Shell.Exec`は同期実行である。Gitリポジトリが巨大な場合、保存時にわずかなラグが生じる可能性がある。通常の開発環境では無視できるレベルだが、ネットワークドライブ上のファイルで運用する場合は注意が必要だ。
- パスの不確実性: このコードは、ExcelファイルがGitリポジトリのルート(あるいはサブディレクトリ)に存在することを前提としている。`ThisWorkbook.Path`をカレントディレクトリに設定するロジックを`GetLatestCommitHash`の冒頭に加えるのが、より堅牢な設計となる。
- バイナリの肥大化抑制: カスタムプロパティは小規模な文字列であるため、ファイルサイズへの影響は皆無に等しい。安心して運用してほしい。
4. 運用の極意
これを導入しただけでは、システムは完成しない。本当の運用は、「このコミットハッシュをどう活用するか」にある。
例えば、配布されたExcelからこのプロパティを抽出し、リポジトリのタグと照合するPowerShellスクリプトをCI環境に配備する。これにより、「現場で使われているExcelが、どの時点のソースと一致しているか」を完全にトレース可能な状態に置くのだ。
VBAはレガシーと言われるが、現代的なDevOpsの思想を注入すれば、依然として強力なビジネスエンジンであり続ける。コードに「出自(Provenance)」を持たせること。それが、真に管理されたプロジェクトへの第一歩である。
