0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

gitとExcelVBAで、ブランチ間の差分をExcelに出力してみたよ!

Last updated at Posted at 2020-03-01

始めに

この記事は、マクロを使って別のアプリケーションを動かせないか、を検証してみたものです。
今回は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みたいな複数指定もいけます、便利!!

とりあえず使い方とコード

使い方としては、

  1. 下記のマクロを全部コピペして、
  2. E5, E7セルにブランチ名を記載したら、
  3. main()を実行

です。E5に指定したブランチ名に対して、E7で指定したブランチの差分が出力されるはずです。
 詳しい説明はさておき、まずはコードを貼ります。コメントも結構書いているので、それだけでも分かる人は何しているか分かるのかな、とも思っています3本当は説明がメンド臭いのであった。

①メインのサブプロシージャ^4
最初に実行するプロシージャです。こいつを適当なボタンに設置してマクロを実行します!

main()

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が存在するフォルダを選択させる関数です。それだけです。

getGitDirPath()
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のパスを定数として定義しているので、パスが通ってなくても動くように設定していますが、環境に応じて定数を書き換えたり、削除したりして下さい。

execCmd
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ライナーの文字列なので、改行コード区切りで分割しています!なぜそうなるかは不明ですが、最後の配列に空白が入るので、返却前に配列の最後の要素を削ってます。

splitResultExecCmd
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

⑤ファイルのパスをセルに出力する関数
差分が得られたら、後は煮るなり焼くなりしましょう!下記では、適当なセルを基準にした方向に並べて出力しています。

layoutFilePath
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

  1. git logでも同じようなことが出来ますが、今回はスルー。

  2. これ、表現として正しいんですかねぇ?誰か教えてくれません?

  3. 分からなくでも大丈夫です。汚いコードを書いた筆者に全ての責任はあります。少しずつ修正しているので、大目に見てやって下さい . . . 。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?