之前寫過小工具將 git diff 程式差異報告轉成網頁好讀版,讓版本控管流程更符合人性,但挑戰總是會接踵而來。同事通報,網頁好讀版在處理某個 Commit 差異報告時爆炸了。未看先猜檔案過大,果然,git diff 輸出檔高達 77MB!!

程式碼是純文字,77MB 都可以寫出賈維斯 Jarvis幫忙寫程式了,而文件、圖檔、dll、pdb、exe 這類二進位檔案幾乎不佔空間,77MB 怎麼撐起來的?

看完內容心中大概有譜。Commit 未依慣例排除 NuGet packages 目錄,dll、pdb 是二進位不會顯示,但套件隨附的 XML 文件或前端套件的 .js 往往數百 KB 到數 MB 起跳,加上數量可觀,撐到上百 MB 也不意外。版控是否放入 NuGet packages 本來就存在討論空間,沒理由禁止;但 packages 下的 js、xml 可以等有用到再顯示,說整個 packages 全文輸出是垃圾資訊,應無人反對。因此,我的思考方向是如何從 git diff 排除這類無意義且耗用大量空間的內容。

這種小事,交給 PowerShell 不難搞定。我的構想是用 Get-Content 逐行讀入 git diff 檔案,以 Pipeline 串接 ForEach-Object 形成串流,讀入一行處理一行,會比將 77MB 內容讀成 string[] 省時也省記憶體;比對部分當然就交給 Regular Expression 了,遇到 diff --git a/file-path b/file-path 時比對路徑,若吻合就不印出全文,改顯示對映的略過理由,例如:Content ignored: packages XML documentation。邏輯並不複雜,程式範例如下:

param (
    [string]$diffPath,
    $filters = @{}
)
$ErrorActionPreference = "STOP"
if (!$filters.Keys -or $filters.Keys.Count -eq 0) {
    Write-Host "Syntax: Filter-GitDiff.ps1 path-to-diff-text @{'/packages/.+[.]xml'='packages XML documentation'}"
    return
}
[int]$seq = -1
[bool]$ignore = $false
[string]$reason = ''
$index = 0
Get-Content $diffPath -Encoding UTF8 | ForEach-Object {
    [string]$line = $_
    $index++
    if ($index % 100 -eq 0) {
        Write-Progress -Activity "Processing Line $index"
    }
    if ($line.StartsWith('diff --git')) {
        $seq = 0
        $ignore = $false
    }
    if (($seq -eq 0)) {
        $filters.Keys | ForEach-Object {
            if ($line -match $_) {
                $ignore = $true
                $reason = $filters[$_]
            }
        }
    }
    if ($ignore -and $seq -eq 5) {
        "Content ignored: $reason"
    } 
    elseif ($ignore -and $seq -gt 5) {
        #ignore
    }
    else {
        $line
    }
    $seq++
}

過濾參數以 Dictionary 方式指定,例如:@{'/packages/.+[.]xml'='packages XML documentation';'/packages/.+[.]js'='packages JS'},可依需求指定多組,並註明略過理由。執行參數範例如下:

.\Filter-GitDiff.ps1 orig.txt @{'/packages/.+[.]xml'='packages XML documentation'} | Out-File filtered.txt -encoding utf8

實際測試,原本 77MB 大檔充斥無意義的 packages XML 文件內容,行數高達 150 萬行:

瘦身後,packages XML 全文濃縮成一行,行數成功降到 5700 行:

檔案也從 77MB 減少到 255KB:

Git 小工具再加一。

PowerShell example to filter out unnecessary content from git diff output.


Comments

Be the first to post a comment

Post a comment