#!/usr/bin/env sh # changed-comments.sh — 列出本次變更裡新增或修改的註解行,供 comment-cleanup 決定清理範圍。 # # 用法: # changed-comments.sh 比對工作區與 HEAD(git diff HEAD),即尚未提交的變更 # changed-comments.sh 比對基準版本(git diff {base}...HEAD),實作完成時用 # 一律在要檢查的存取庫目錄下執行;本腳本不吃路徑參數,也不切換目錄。 # # 輸出(TSV,一列一行註解,三欄,欄位之間一個 tab,只走 stdout): # 1 檔案 路徑,相對存取庫根目錄 # 2 行號 該註解行在新版檔案裡的行號,正整數 # 3 內容 該行原文;行內的 tab 換成一個空白,欄位才不會錯位 # # 結束碼: # 0 有結果,至少印出一列 # 1 沒有結果,本次變更沒有新增或修改的註解行(呼叫端回報「無發現」) # 2 參數或環境錯誤:參數超過一個、目前目錄不在 git 工作區、基準版本無效、缺 git 或 awk # # 判準的來源:註解行樣式與「不受本規則限制的非程式碼副檔名」兩份判準,都沿用 jsc-hooks 的 # hooks/comment-scope.sh(scan_file 裡的那兩份),一字不差地照抄。那支 hook 是規則實作的 # 正本,這裡只是把同一份判準搬到 git diff 上;哪天正本改了樣式,這裡要跟著改,不得各自演化。 # 跳過非程式碼檔不是可有可無的:markdown 的標題行開頭就是 #,不跳過就會把整份文件當成註解。 set -u usage() { echo '用法:changed-comments.sh [base](不給基準時比對工作區與 HEAD)' >&2 exit 2 } [ "$#" -le 1 ] || usage for cmd in git awk; do command -v "$cmd" >/dev/null 2>&1 || { echo "錯誤:環境缺 $cmd,無法列出變更的註解行。" >&2 exit 2 } done git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo '錯誤:目前目錄不在 git 工作區內,取不到變更範圍。' >&2 exit 2 } # git diff 的失敗一律原樣往上帶:判不出範圍卻回「無發現」,等於把環境問題講成沒有東西要清。 if [ "$#" -eq 1 ]; then base=$1 case "$base" in -*) usage ;; esac git rev-parse --verify --quiet "$base^{commit}" >/dev/null 2>&1 || { echo "錯誤:基準版本「$base」不是有效的 commit。" >&2 exit 2 } DIFF=$(git diff --no-color -U0 "$base...HEAD" 2>&1) || { printf '%s\n' "$DIFF" >&2 exit 2 } else DIFF=$(git diff --no-color -U0 HEAD 2>&1) || { printf '%s\n' "$DIFF" >&2 exit 2 } fi # 樣式走環境變數交給 awk:走 -v 的話 awk 會先解釋字串裡的跳脫序列,樣式中的 \* 會被吃成 # 量詞 *,整條 ERE 的意思就變了。ENVIRON 不做這層處理,樣式進到 awk 時與正本一字不差。 COMMENT_RE='^[[:space:]]*(//|#|--|\*|/\*|