今天遇到一個問題,想從 Git 版控找出圖檔何時被改壞。圖檔不像程式碼能用 git blame 直接找出哪一行何時被誰修改,但至少可以知道檔案在何時被誰改過,再從 Commit 調閱當時的版本加以比對。這個需求肯定有方便的 GUI 工具可以做到,但我想練習用指令完成。

假設 Git 版控有四次 Commit,有個 dog.png 圖檔被改過三次:

要找出檔案在哪些 Commit 被異動過,基本指令是 git log -- path/fileName ( -- 用來分隔選項參數與檔名,-- 前方可加上 --oneline --pretty 等選擇性參數,後方為要查詢的檔案對象),再依需求加上 git log 參數,以下是我常用的寫法:

git log -- dog.png
git log --oneline -- dog.png
git log --date=format:"%Y-%m-%d %H:%M:%S" --pretty=format:"%h %ad %s %an" -- dog.png

知道 Commit ID,我們就能透過 git checkout commit_id path/file 將檔案還原回某次 Commit 的版本,或是用 git show commit_id:path/file 查看內容,若不是文字檔,則可加上 > 導向寫成檔案 git show commit_id:path/file > saveFilePath

git checkout 64dfd59 ./dog.png
git show 6f443d0:./dog.png > dog_check.png

基本上,學會以上指令就能查出檔案在哪些 Commit 被異動過,並調閱特定版本出來比對,已滿足日常需求。但我手又癢了,決定寫個 PowerShell 把歷屆版本全部轉出來,檔名註明存入時間,一次對照個夠。

param (
    [Parameter(Mandatory = $true)]
    [string]$fileName,
    [Parameter(Mandatory = $true)]
    [string]$saveFolder
)
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$gitLog = "git log --date=format:`"%Y-%m-%d %H:%M:%S`" --pretty=format:`"%h %ad %s %an`" -- $fileName"
(& "cmd.exe" '/c' $gitLog | ForEach-Object {
    $p = $_.Split(' ')
    return [PSCustomObject]@{ CommitId = $p[0]; Date = $p[1]; Time = $p[2]; }
}) | ForEach-Object {
    $saveFileName = Join-Path $saveFolder "$($_.Date)T$($_.Time.Replace(':',''))-$fileName"
    $gitShow = "git show $($_.CommitId):$fileName > $saveFileName"
    & "cmd.exe" '/c' $gitShow
}

成功!

對上述 PowerShell 寫法有興趣,可參考下列文章介紹的技巧:

Tips of how to get specific file version from Git commit.


Comments

# by 小魚

神~

Post a comment