こんにちは!プロジェクト管理の現場で、VBAと格闘する日々を送っていませんか?
「マクロの記録」から一歩踏み出し、独自の自動化ツールを作り始めると、避けて通れないのが「バージョン管理」の壁です。
ExcelやWordならまだしも、Microsoft Project(MSP)の `.mpp` ファイルはバイナリ形式が主流。Gitでそのまま差分管理するのは至難の業です。「いま動かしているこのスケジュール、本当に最新のコード(プログラム)と同期しているんだっけ?」と不安になった経験、ありませんか?
今回は、そんな現場の悩みを鮮やかに解決する「プロジェクトのメタデータにGitのコミットハッシュを自動で埋め込むテクニック」を伝授します。
ここをクリアすれば、Project VBAのイベントハンドリングと外部プロセス連携の基本はバッチリですよ。さあ、ワンランク上のエンジニアへ一緒にステップアップしましょう!
—
なぜ、プロジェクトのメタデータにGitハッシュが必要なのか?
大規模なプロジェクトになると、スケジュール(`.mpp`)と、それを制御するVBAマクロや外部スクリプトのバージョンが乖離しがちです。
「先週の古いスケジュールファイルで進捗を報告してしまった…」
「どのソースコードの状態で引いたベースラインなのか分からない…」
こんなヒューマンエラーを防ぐため、「プロジェクトファイルを保存した瞬間、裏でGitの最新コミットハッシュを取得し、プロジェクトのプロパティ(メタデータ)に自動刻印する」仕組みを作ります。これにより、ファイルを見るだけで「どの時点のコードと同期しているか」が一目で分かるようになります。
—
仕組みの全体像
今回の実装では、以下の2つの要素を組み合わせます。
1. Gitコマンドの実行: VBAからWindowsのシェル(WScript.Shell)を叩き、`git rev-parse HEAD`(現在のコミットハッシュを取得するコマンド)を実行する。
2. プロジェクトプロパティへの書き込み: 取得したハッシュを、Projectの「ユーザー定義フィールド(Enterprise Custom Fields / プロジェクト情報)」、あるいは簡易的に `ProjectSummaryTask` のメモなどに書き込む。
今回は、最も手軽かつ確実な「プロジェクト情報のユーザー設定属性(BuiltinDocumentProperties または CustomDocumentProperties)」を活用します。
—
実装ステップ:VBAコードの記述
さあ、実際にコードを書いていきましょう。
MS ProjectのVBAエディタ(`Alt + F11`)を開き、`ThisProject` モジュールにコードを記述します。
なぜ `ThisProject` なのか?それは、プロジェクトの「保存イベント(`ProjectBeforeSave`)」をキャッチするためです。
1. イベントの準備とコード全文
以下のコードを `ThisProject` のコードウィンドウに貼り付けてください。
‘Option Explicitは必ず記述するプロの作法です
Option Explicit
‘ プロジェクトが保存される直前に自動発火するイベント
Private Sub Project_ProjectBeforeSave(ByVal pj As Project, ByVal SaveAsUI As Boolean, Cancel As Boolean)
On Error GoTo ErrorHandler
Dim gitHash As String
Dim targetPath As String
‘ 1. 現在開いているプロジェクトのファイルパスを取得
targetPath = pj.Path
‘ まだ一度も保存されていない新規ファイルの場合はパスがないため処理をスキップ
If targetPath = “” Then
MsgBox “プロジェクトがまだ保存されていません。一度保存してからGit連携を行ってください。”, vbExclamation, “Git連携警告”
Exit Sub
End If
‘ 2. Gitのコミットハッシュを取得する
gitHash = GetLatestGitCommitHash(targetPath)
If gitHash <> “” Then
‘ 3. プロジェクトのカスタムプロパティ(ドキュメント情報)にハッシュを書き込む
Call SetCustomProperty(pj, “GitCommitHash”, gitHash)
Call SetCustomProperty(pj, “GitSyncTime”, Format(Now, “yyyy-mm-dd HH:nn:ss”))
‘ ユーザーへのさりげないフィードバック(必要に応じてコメントアウト可)
Debug.Print “【Git連携】コミットハッシュをメタデータに埋め込みました: ” & gitHash
Else
Debug.Print “【Git連携】Gitリポジトリが見つからないか、ハッシュの取得に失敗しました。”
End If
Exit Sub
ErrorHandler:
MsgBox “Gitハッシュの埋め込み中にエラーが発生しました: ” & Err.Description, vbCritical, “VBAエラー”
End Sub
/
- 指定されたパスを起点にGitの最新コミットハッシュを取得する関数
/
Private Function GetLatestGitCommitHash(ByVal repoPath As String) As String
Dim shell As Object
Dim exec As Object
Dim cmd As String
Dim result As String
‘ コマンドプロンプトでGitコマンドを実行
‘ カレントディレクトリをプロジェクトのパスに移動し、ショートハッシュ(–short)を取得
cmd = “cmd.exe /c cd /d “”” & repoPath & “”” && git rev-parse –short HEAD”
Set shell = CreateObject(“WScript.Shell”)
On Error Resume Next
‘ 外部プロセスの実行と標準出力のキャプチャ
Set exec = shell.Exec(cmd)
If Err.Number <> 0 Then
GetLatestGitCommitHash = “”
Exit Function
End If
On Error GoTo 0
‘ 出力結果から余計な改行などを取り除く
result = exec.StdOut.ReadAll
result = Trim(Replace(result, vbCrLf, “”))
result = Trim(Replace(result, vbLf, “”))
GetLatestGitCommitHash = result
End Function
/
- プロジェクトのカスタムドキュメントプロパティに値を設定するヘルパー関数
/
Private Sub SetCustomProperty(ByVal pj As Project, ByVal propName As String, ByVal propValue As String)
Dim prop As Object
Dim isExist As Boolean
isExist = False
‘ 既存のプロパティを走査し、存在すれば上書き、なければ新規追加
For Each prop In pj.CustomDocumentProperties
If prop.Name = propName Then
prop.Value = propValue
isExist = True
Exit For
End If
Next prop
If Not isExist Then
‘ 3 = msoPropertyTypeString (文字列型)
pj.CustomDocumentProperties.Add Name:=propName, LinkToContent:=False, Type:=3, Value:=propValue
End If
End Sub
—
コードの深掘り・重要なポイント解説
ここからは、チーフアーキテクトの視点から、このコードのキモを解説します。
① `ThisProject` モジュールとイベントの力
通常の標準モジュール(`Module1` など)に書いたマクロは、ユーザーがボタンを押さないと動きません。しかし、`ThisProject` に書いた `Project_ProjectBeforeSave` は、ユーザーが「上書き保存」または「名前を付けて保存」を押した瞬間に、背後で自動的に実行されます。 これにより、バージョン情報の入れ忘れを完全に防ぐことができます。
② WScript.ShellによるGitコマンドの乗っ取り
VBA単体ではGitの内部構造を読み取れません。そこで `CreateObject(“WScript.Shell”)` を使い、OSのコマンドプロンプト(`cmd.exe`)をこっそり裏で動かしています。
`cd /d “”” & repoPath & “””` でプロジェクトファイルが存在するフォルダに移動し、`git rev-parse –short HEAD` で「現在チェックアウトされているコミットの短いハッシュ値(例: `a1b2c3d`)」を取得しています。
③ 堅牢なエラーハンドリング(防御的プログラミング)
もし、ユーザーがGit管理されていない(=ただのローカルフォルダにある)プロジェクトファイルを保存しようとしたらどうなるでしょうか?
`git` コマンドはエラーを吐きます。ここでプログラムがクラッシュして保存自体が失敗してしまったら、ユーザーは大激怒してしまいますよね。
そのため、`On Error Resume Next` や、ファイルパスが空欄(`repoPath = “”`)の場合のガードを挟み、「Gitが使えない環境でも、通常のファイル保存は絶対に阻害しない」という堅牢な設計にしています。
—
開発現場でよくある「罠」と対策
1. 「ファイルパスが取得できません」というエラーが出る
- 原因: 新規作成してまだ一度も保存していない `.mpp` ファイルに対して保存イベントが走った場合、`pj.Path` は空文字になります。
- 対策: コード内の `If targetPath = “” Then` で弾いているため安全ですが、テスト時は必ず一度ディスク上に保存してから動作確認を行ってください。
2. 社内セキュリティで `WScript.Shell` がブロックされる
- 原因: 厳格なセキュリティポリシーが敷かれた企業端末では、VBAから外部プロセスを起動するオブジェクトが制限されている場合があります。
- 対策: その場合は情報システム部門に相談するか、テキストファイル経由でハッシュを読み込むなどの代替案を検討してください。
—
まとめ:コードとスケジュールを完全にシンクロさせよう
今回は、Project VBAのイベントハンドリングと外部プロセス連携を駆使し、「プロジェクトファイルの保存時にGitのコミットハッシュを自動刻印する」という上級テクニックをご紹介しました。
この仕組みを導入すれば、後から「どのソースコードのバージョンでこの工程表を作ったんだっけ?」と頭を抱えることはもうなくなります。
「ここをクリアすれば、Project VBAの基本はバッチリですよ!」
ぜひあなたの現場でもこのコードを導入し、スマートでモダンなプロジェクト管理を実現してください。それでは、次のアーキテクチャ解説でお会いしましょう!
