5

PowerShell 練習 - Git diff 瘦身工具

 3 years ago
source link: https://blog.darkthread.net/blog/ps-filter-git-diff/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Git diff 瘦身工具-黑暗執行緒

之前寫過小工具將 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 小工具再加一。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK