始めに
この記事は、マクロを使って別のアプリケーションを動かせないか、を検証してみたものです。
今回はgitをコマンドプロンプト経由で使ってみました!
(本当は直接gitを操作したかったけど、実行方法がイメージできなかった . . . )
毎度のことですが、記事の内容に関して「ここおかしい!」とかあったら、コメントお願いします。
読了時間 : 10 min.(目安)
やりたいこと
Excelにブランチの差分をその種類?(追加・変更・複製・削除)ごとに出力します!
(こんな感じでやります!みたいなgifをここに載せる予定です。)
作業環境
以下の環境で動作確認しています
OS : Windows10 Home
git : 2.22.0.windows.1
Excel : 2016 MSO 32bit
本題の前に
本題に入る前に、gitに関してちょっとだけ補足的な説明です。「そんなのいいからコードはよ!!」というあなたは適当に読み飛ばして下さい。
gitでブランチ間の差分、それもファイル名だけを見ようと思ったら、以下のようなコードを実行すると思います1。
# master と develop の差分を見る
> git diff master..develop --name-only
↑の場合だとmaster
と比較してdevelop
ブランチで、
・どのファイルを新たに作成したか
・どのファイルを修正したか
・削除したファイルは何か
などを確認できます。さらに差分の種類?2ごとに表示するなら、--diff-filter
を付けて
# 新規追加したファイルだけ差分として表示
> git diff master..develop --name-only --diff-filter=A
とすればOK!指定する文字は、Aは追加(Added)、Mは修正(Modified)、Cは複製(copied)、Dは削除(Deleted)を表してます。--diff-filter=AM
みたいな複数指定もいけます、便利!!
とりあえず使い方とコード
使い方としては、
- 下記のマクロを全部コピペして、
- E5, E7セルにブランチ名を記載したら、
- main()を実行
です。E5に指定したブランチ名に対して、E7で指定したブランチの差分が出力されるはずです。
詳しい説明はさておき、まずはコードを貼ります。コメントも結構書いているので、それだけでも分かる人は何しているか分かるのかな、とも思っています3。本当は説明がメンド臭いのであった。
①メインのサブプロシージャ^4
最初に実行するプロシージャです。こいつを適当なボタンに設置してマクロを実行します!
Option Explicit
Public Const firstRow As Long = 7 ' 出力セルの開始行
Public Const firstColumn As Long = 5 ' 出力セルの開始列
Sub main()
Dim aryDiffOp() As Variant ' ファイルの差分をフィルタリングするオプション
Dim dirPath As String ' リポジトリのパス
Dim aryFilePath As Variant ' ファイルのパスを格納する配列
Dim diffOp As Variant ' 差分オプションのループ変数
Dim ii As Long : ii = firstRow ' 出力する際のループ変数
' 差分を取得するリポジトリのパスを設定
dirPath = getGitDirPath()
' 差分オプションの設定
aryDiffOp = Array("A", "M", "C", "D")
' 新規・変更・複製・削除されたファイルをそれぞれ出力する
For Each diffOp In aryDiffOp
' 変更内容ごとにファイルを取得
aryFilePath = execCmd(dirPath, diffOp)
If IsNull(aryFilePath) Then
' 差分が無い場合
Call layoutFilePath(Null, diffOp, ii)
Else
' 差分がある場合
Call layoutFilePath(aryFilePath, diffOp, ii)
End If
Next diffOp
MsgBox "終了!"
End Sub
②gitフォルダのパスを取得する関数
エクスプローラを起動して、.git
が存在するフォルダを選択させる関数です。それだけです。
Function getGitDirPath() As String
Dim filePath As String
' gitフォルダを1つだけ選択させる
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
If .Show Then
' フォルダを選択した場合
getGitDirPath = .SelectedItems(1) & "\"
Else
' フォルダを選択していない場合
MsgBox "フォルダが存在しません"
End ' マクロを終了させる
End If
End With
End Function
③gitコマンドを実行する関数
今回の主役とも言うべき関数です!!コマンドをわざわざ配列に分けて格納しているのは、完全に趣味です!!
gitのパスを定数として定義しているので、パスが通ってなくても動くように設定していますが、環境に応じて定数を書き換えたり、削除したりして下さい。
Function execCmd(ByVal dirPath As String, ByVal diffOp As String) As Variant
Dim sh As New IWshRuntimeLibrary.WshShell ' WshShellクラスオブジェクト
Dim ex As WshExec ' Execメソッド戻り値
Dim diffFromBranch As String: diffFromBranch = Cells(5, 5).Value ' 差分比較元のブランチ
Dim diffToBranch As String: diffToBranch = Cells(5, 7).Value ' 差分比較先のブランチ
Dim cmd ' 実行コマンド
Dim aryCmd(1) ' 実行コマンド配列
Dim gitCmd ' gitコマンド
Dim aryGitCmd(5) ' gitコマンド配列
Dim result As String ' コマンド実行結果
Const git As String = """C:\Program Files\Git\cmd\git.exe"""
'// gitコマンドを配列に格納
aryGitCmd(0) = git
aryGitCmd(1) = "-C " & dirPath
aryGitCmd(2) = "diff"
aryGitCmd(3) = diffFromBranch & ".." & diffToBranch
aryGitCmd(4) = "--name-only"
aryGitCmd(5) = "--diff-filter=" & diffOp
'// gitコマンドを空白区切りで連結
gitCmd = Join(aryGitCmd, " ")
MsgBox "gitCmd > " & gitCmd
'// 実行する順にコマンドを配列に格納
aryCmd(0) = "C:"
aryCmd(1) = gitCmd
'// コマンドを連結
cmd = Join(aryCmd, " & ")
MsgBox "cmd > " & cmd
'// コマンド実行
Set ex = sh.Exec("cmd.exe /C " & cmd)
'// コマンド失敗時
If (ex.Status = WshFailed) Then
'// 処理を抜ける
MsgBox "処理に失敗しました"
Exit Function
End If
'// コマンド実行中は待ち
Do While (ex.Status = WshRunning)
DoEvents
Loop
'// 標準出力の結果を表示する
result = ex.StdOut.ReadAll
execCmd = splitResultExecCmd(result)
End Function
④差分を配列に格納する関数
差分をファイルパスごとに配列に格納して、呼び出し元のmainへと返しています。差分が無かった場合は、nullを返却しています。
↑の関数で出力された結果は、1ライナーの文字列なので、改行コード区切りで分割しています!なぜそうなるかは不明ですが、最後の配列に空白が入るので、返却前に配列の最後の要素を削ってます。
Function splitResultExecCmd(ByVal resultExecCmd As String) As Variant
Dim aryFilePath As Variant ' ファイルのパスを格納する配列
If Len(resultExecCmd) <> 0 Then
' 差分がある場合の処理
aryFilePath = Split(resultExecCmd, vbLf)
ReDim Preserve aryFilePath(UBound(aryFilePath) - 1)
splitResultExecCmd = aryFilePath
Else
' 差分が無かった場合の処理
splitResultExecCmd = Null
End If
End Function
⑤ファイルのパスをセルに出力する関数
差分が得られたら、後は煮るなり焼くなりしましょう!下記では、適当なセルを基準にした方向に並べて出力しています。
Sub layoutFilePath(ByRef aryFilePath As Variant, ByVal diffOp As String, ByRef i As Long )
Dim filePath As Variant ' 各ファイルのパス
' 差分の種類を出力
Cells(i, firstColumn) = diffOp
' 差分の有無で出力内容を分岐
If IsNull(aryFilePath) Then
Cells(i, firstColumn + 1) = "差分なし"
i = i + 1
Else
' ファイルパスを1つずつ出力
For Each filePath In aryFilePath
Cells(i, firstColumn + 1) = filePath
i = i + 1
Next filePath
End If
End Sub
終わりに
最後まで読んで下さり、ありがとうございました。
ひとりごと
毎回「始めに」で何を書くか迷っているんですよね . . . (みんなどうしているのかな?)
読み物として楽しい記事を作りたいので、イイ感じに書けるように修行ですね!
参考
1.VBAでコマンドプロンプトの起動とコマンドの実行を行う
2.Nullを判定する-IsNull関数
3.【VBA入門】配列の初期化(ReDim、Preserve、Array、Erase)
4.VBAでフォルダパスを取得する
5.Application.FileDialog プロパティ (Excel)
6.【VBA入門】Functionの使い方(呼び出し、引数、戻り値)
7.VarType Office TANAKA