使用 Git-LFS + 一點技巧管理部落格圖片

Wi1dcard發表於2019-06-20

這可能是截至目前我認為最優雅的部落格圖片管理方案沒有之一。

背景

早期

最早,我的部落格採用單臺 PHP 伺服器搭建動態部落格,將圖片儲存至伺服器並定期備份。而訪客則是通過 CDN 加速,以便快速載入圖片。

缺點:

  • 備份不及時,大量冗餘資料。
  • 圖片管理操作不便。

中期

後來,嘗試改用七牛 OSS + CDN 全家桶,資料量和流量不大,所以一直在用免費額度。另外,截止 2018 年的某個月,早期註冊的老使用者是一直擁有 無需備案 的無限制測試域名的(然而後來就收到了強制回收的郵件... 國內企業果然不可信)。

缺點:

  • 七牛免費服務真心不靠譜,國外訪問巨卡,導致我日常在牆外瀏覽自己部落格都特別慢。
  • 管理起來同樣不方便,備份也不方便。對於我這個潔癖強迫症來說,有多餘 Dangling 的檔案存在簡直不可饒恕。
  • 資料放在國內的第三方服務,說不定哪天有什麼違規被查水錶,方。

後期

更換為 Hexo 後,一直在用大佬的圖床:sm.ms

直到近期,寫部落格時截圖完畢想要上傳,卻偶然發現圖床頁面提示:維護升級中,請稍後訪問。

接下來大約一整天左右,一直處於無法上傳的狀態。用過各種免費圖床網盤的我不禁內心一緊:難不成,又是要涼了?於是趕緊把之前上傳的所有圖片統統排查一遍,發現只有極個別圖片出現 404。

缺點:

  • 如上文所說,免費圖床不存在 SLA,可靠性未知,雖然 sm.ms 大佬已經撐了很久,也相對比較靠譜,但還是不放心。
  • 每次截圖完畢還需要上傳,麻煩。

雖然目前基本未受到影響,但卻讓我忽然警醒 —— 或許是時候嘗試一下不使用外部圖床了。

方案

基本思路如下,大致分為兩部分:

儲存(Git-LFS)

根據以上問題,首先需要解決的就是如何儲存。直接儲存在 Git Repo 內肯定不合適。Git 無法 Diff 二進位制檔案,如果在部落格更新和重構過程中優化、修改、移動這些圖片檔案,那對於 Git 倉庫來說將是「爆炸性」的,你會看到倉庫大小成倍增長,CI/CD 執行 Clone 和 Build 時會嚴重拖慢速度。雖然有方法可 後期清理,但我並不喜歡這種怪異的折中方案,除非倉庫已經被二進位制檔案「汙染」。

針對這個問題,Git-LFS 是個不錯的解決方案。它是一個 Git 外掛,是由 GitHub 而非 Git 官方推出,儘管官網風格的確很像?。

該專案的基本原理很簡單,在本地 Git 上安裝一系列 Hooks,通過鉤子「攔截」各類操作,例如 Push / Pull / Checkout。在執行這些操作時,自動從 Git-LFS 伺服器下載由其管理的二進位制檔案。

在真正的 Git 倉庫內,實際上只保留該二進位制檔案的雜湊等資料。而實實在在的檔案資料儲存在 Git-LFS 伺服器內,在需要的時候才下載。這樣既節省倉庫的儲存空間,另一方面也能節省你的時間和頻寬。

安裝使用極其簡單,以 macOS 為例:

brew install git-lfs
git lfs install # 安裝 Hooks
cd your-repo

告知 LFS 追蹤某些檔案,可使用類似 .gitignore 檔案內的 glob 語法,以 *.png 為例:

git lfs track "*.png"

以上命令會建立 .gitattributes 檔案,不要刪除它,並確保提交到倉庫內。

好了,接下來正常執行其它 Git 操作即可。Push 到 GitHub 後,在 Web 頁面開啟你的檔案,可看到以下字樣:

Stored with Git LFS

說明檔案已經被 Git-LFS 接管並儲存啦。

最後,需要注意一點:由於 Git-LFS 是一個「第三方標準與實現」,故並不是所有 Git 服務都支援 LFS 儲存。

新增(Shell 指令碼)

我平時使用 macOS 自帶的 Screenshot 工具,與多數截圖工具類似,它可以將圖片儲存至剪貼簿。那麼,如何快速將剪貼簿內的圖片輸出為檔案,且按照一定格式組織檔名呢?這需要一點小技巧。

推薦一個名為 jcsalterego/pngpaste 的小工具,顧名思義,它就像 macOS 下的 pbpaste 一樣,可以在終端快速讀取剪貼簿並匯出,正如在專案首頁上描述的那樣:

Paste PNG into files, much like pbpaste does for text.

接下來,我需要一個「小指令碼」,進行一點包裝工作,我將它儲存為 ./image.sh. 為 Hexo 部落格的根目錄,下同。

#!/bin/bash -eu

dir=$(dirname $0) # 該指令碼所在目錄,用於定點陣圖片儲存路徑,可替換為其它
tmp_file=$(mktemp) # 生成臨時檔案路徑

pngpaste $tmp_file # 將剪貼簿圖片儲存至臨時檔案

hash=$(md5 < $tmp_file) # 計算圖片的雜湊值,用於唯一檔名
img="/resources/$hash.png" # 拼接圖片 URI

mv $tmp_file "$dir/source$img" # 將臨時檔案移動為最終圖片檔案
echo "![]($img)" | tee >(pbcopy) # 生成 Markdown 格式的圖片連結,輸出至 STDOUT 同時寫入剪貼簿

搞定。此處不採用拼接時間或隨機字串,而是雜湊值作為檔名的原因,是為了保證冪等性。

最終效果為,截圖軟體截圖,終端內執行 ./image.sh 即可將剪貼簿內的圖片儲存為 ./source/resources/$hash.png,簡單到幾乎不能再簡單。

完美解決 Git 倉庫大小問題、上傳麻煩問題;最重要的是,圖片管理與本地檔案操作無異(實際就是在操作本地檔案?),無縫使用各類命令或 GUI。

我感謝自己平凡,敢愛敢恨沒負擔。
我感謝自己不凡,可愛可恨都包攬。

相關文章