[{"data":1,"prerenderedAt":1390},["ShallowReactive",2],{"blog:\u002Fblog\u002Fgit\u002Fhusky-and-commitlint":3},{"id":4,"title":5,"author":6,"body":7,"category":1377,"date":1378,"description":1379,"draft":1380,"extension":1381,"image":1382,"meta":1383,"navigation":214,"path":1384,"seo":1385,"series":1382,"seriesOrder":1382,"seriesTitle":1382,"stem":1386,"tags":1387,"updatedAt":1388,"__hash__":1389},"blog\u002Fblog\u002Fgit\u002Fhusky-and-commitlint.md","自動檢查 Git commit 與 branch 名稱的格式","charles",{"type":8,"value":9,"toc":1370},"minimark",[10,14,19,34,64,70,88,92,100,116,120,148,152,163,697,710,740,749,975,979,982,993,1009,1018,1108,1119,1158,1168,1172,1178,1181,1366],[11,12,13],"p",{},"以下以 pnpm 跟已經有 git 初始化的專案為例。",[15,16,18],"h2",{"id":17},"安裝-husky","安裝 husky",[20,21,22],"ol",{},[23,24,25,26,33],"li",{},"參考",[27,28,32],"a",{"href":29,"rel":30},"https:\u002F\u002Ftypicode.github.io\u002Fhusky\u002Fget-started.html",[31],"nofollow","官網指引","，以 pnpm 為例：",[35,36,41],"pre",{"className":37,"code":38,"language":39,"meta":40,"style":40},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","pnpm add --save-dev husky\n","bash","",[42,43,44],"code",{"__ignoreMap":40},[45,46,49,53,57,61],"span",{"class":47,"line":48},"line",1,[45,50,52],{"class":51},"sbgvK","pnpm",[45,54,56],{"class":55},"s_sjI"," add",[45,58,60],{"class":59},"stzsN"," --save-dev",[45,62,63],{"class":55}," husky\n",[20,65,67],{"start":66},2,[23,68,69],{},"初始化設定",[35,71,73],{"className":37,"code":72,"language":39,"meta":40,"style":40},"pnpm exec husky init\n",[42,74,75],{"__ignoreMap":40},[45,76,77,79,82,85],{"class":47,"line":48},[45,78,52],{"class":51},[45,80,81],{"class":55}," exec",[45,83,84],{"class":55}," husky",[45,86,87],{"class":55}," init\n",[15,89,91],{"id":90},"安裝-commitlint","安裝 commitlint",[20,93,94],{},[23,95,25,96,33],{},[27,97,32],{"href":98,"rel":99},"https:\u002F\u002Fcommitlint.js.org\u002Fguides\u002Fgetting-started.html",[31],[35,101,103],{"className":37,"code":102,"language":39,"meta":40,"style":40},"pnpm add --save-dev @commitlint\u002F{cli,config-conventional}\n",[42,104,105],{"__ignoreMap":40},[45,106,107,109,111,113],{"class":47,"line":48},[45,108,52],{"class":51},[45,110,56],{"class":55},[45,112,60],{"class":59},[45,114,115],{"class":55}," @commitlint\u002F{cli,config-conventional}\n",[20,117,118],{"start":66},[23,119,69],{},[35,121,123],{"className":37,"code":122,"language":39,"meta":40,"style":40},"echo \"export default { extends: ['@commitlint\u002Fconfig-conventional'] };\" > commitlint.config.js\n",[42,124,125],{"__ignoreMap":40},[45,126,127,131,135,138,141,145],{"class":47,"line":48},[45,128,130],{"class":129},"sptTA","echo",[45,132,134],{"class":133},"sjJ54"," \"",[45,136,137],{"class":55},"export default { extends: ['@commitlint\u002Fconfig-conventional'] };",[45,139,140],{"class":133},"\"",[45,142,144],{"class":143},"smGrS"," >",[45,146,147],{"class":55}," commitlint.config.js\n",[15,149,151],{"id":150},"針對-commit-訊息的格式檢查","針對 commit 訊息的格式檢查",[20,153,154],{},[23,155,156,157,162],{},"將 commitlint.config.js 檔案改為以下檔案\n此操作會檢查 commit 訊息是否符合 conventional commit 的格式，並且參照 ",[27,158,161],{"href":159,"rel":160},"https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=devCharles5277.git-commit-plugin-with-gitmoji",[31],"git commit plugin with gitmoji"," 的 emoji 來區分不同的 commit 類型。",[35,164,168],{"className":165,"code":166,"language":167,"meta":40,"style":40},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","export default {\n  extends: [\"@commitlint\u002Fconfig-conventional\"],\n\n  \u002F\u002F 自定義解析器：支援 \"✨ feat: message\" 格式\n  parserPreset: {\n    parserOpts: {\n      headerPattern:\n        \u002F^(✨ feat|🐛 fix|🧹 chore|🔨 refactor|🧪 test|🎨 style|📝 docs|📦 build|👷 ci|⏪ revert|🚀 deploy|🎉 init): (.+)$\u002F,\n      headerCorrespondence: [\"type\", \"subject\"],\n    },\n  },\n\n  rules: {\n    \u002F\u002F 允許的 commit 類型（包含 emoji）\n    \"type-enum\": [\n      2,\n      \"always\",\n      [\n        \"✨ feat\",\n        \"🐛 fix\",\n        \"🧹 chore\",\n        \"🔨 refactor\",\n        \"🧪 test\",\n        \"🎨 style\",\n        \"📝 docs\",\n        \"📦 build\",\n        \"👷 ci\",\n        \"⏪ revert\",\n        \"🚀 deploy\",\n        \"🎉 init\",\n      ],\n    ],\n    \u002F\u002F 關閉 type-case 檢查（因為我們的 type 包含 emoji 和空格）\n    \"type-case\": [0],\n    \u002F\u002F 關閉 type-empty 檢查（由 type-enum 處理）\n    \"type-empty\": [0],\n    \u002F\u002F 允許 subject 以小寫或大寫開頭（中文沒有大小寫）\n    \"subject-case\": [0],\n  },\n};\n","js",[42,169,170,183,209,216,223,233,243,252,349,380,386,392,397,407,413,430,439,452,458,470,481,492,503,514,525,536,547,558,569,580,591,599,607,613,634,640,660,666,686,691],{"__ignoreMap":40},[45,171,172,176,179],{"class":47,"line":48},[45,173,175],{"class":174},"sVHd0","export",[45,177,178],{"class":174}," default",[45,180,182],{"class":181},"sP7_E"," {\n",[45,184,185,189,192,196,198,201,203,206],{"class":47,"line":66},[45,186,188],{"class":187},"skxfh","  extends",[45,190,191],{"class":181},":",[45,193,195],{"class":194},"su5hD"," [",[45,197,140],{"class":133},[45,199,200],{"class":55},"@commitlint\u002Fconfig-conventional",[45,202,140],{"class":133},[45,204,205],{"class":194},"]",[45,207,208],{"class":181},",\n",[45,210,212],{"class":47,"line":211},3,[45,213,215],{"emptyLinePlaceholder":214},true,"\n",[45,217,219],{"class":47,"line":218},4,[45,220,222],{"class":221},"sutJx","  \u002F\u002F 自定義解析器：支援 \"✨ feat: message\" 格式\n",[45,224,226,229,231],{"class":47,"line":225},5,[45,227,228],{"class":187},"  parserPreset",[45,230,191],{"class":181},[45,232,182],{"class":181},[45,234,236,239,241],{"class":47,"line":235},6,[45,237,238],{"class":187},"    parserOpts",[45,240,191],{"class":181},[45,242,182],{"class":181},[45,244,246,249],{"class":47,"line":245},7,[45,247,248],{"class":187},"      headerPattern",[45,250,251],{"class":181},":\n",[45,253,255,258,261,265,269,272,275,277,280,282,285,287,290,292,295,297,300,302,305,307,310,312,315,317,320,322,325,328,331,333,336,339,341,344,347],{"class":47,"line":254},8,[45,256,257],{"class":133},"        \u002F",[45,259,260],{"class":174},"^",[45,262,264],{"class":263},"s-KJb","(",[45,266,268],{"class":267},"sQRbd","✨ feat",[45,270,271],{"class":143},"|",[45,273,274],{"class":267},"🐛 fix",[45,276,271],{"class":143},[45,278,279],{"class":267},"🧹 chore",[45,281,271],{"class":143},[45,283,284],{"class":267},"🔨 refactor",[45,286,271],{"class":143},[45,288,289],{"class":267},"🧪 test",[45,291,271],{"class":143},[45,293,294],{"class":267},"🎨 style",[45,296,271],{"class":143},[45,298,299],{"class":267},"📝 docs",[45,301,271],{"class":143},[45,303,304],{"class":267},"📦 build",[45,306,271],{"class":143},[45,308,309],{"class":267},"👷 ci",[45,311,271],{"class":143},[45,313,314],{"class":267},"⏪ revert",[45,316,271],{"class":143},[45,318,319],{"class":267},"🚀 deploy",[45,321,271],{"class":143},[45,323,324],{"class":267},"🎉 init",[45,326,327],{"class":263},")",[45,329,330],{"class":267},": ",[45,332,264],{"class":263},[45,334,335],{"class":59},".",[45,337,338],{"class":143},"+",[45,340,327],{"class":263},[45,342,343],{"class":174},"$",[45,345,346],{"class":133},"\u002F",[45,348,208],{"class":181},[45,350,352,355,357,359,361,364,366,369,371,374,376,378],{"class":47,"line":351},9,[45,353,354],{"class":187},"      headerCorrespondence",[45,356,191],{"class":181},[45,358,195],{"class":194},[45,360,140],{"class":133},[45,362,363],{"class":55},"type",[45,365,140],{"class":133},[45,367,368],{"class":181},",",[45,370,134],{"class":133},[45,372,373],{"class":55},"subject",[45,375,140],{"class":133},[45,377,205],{"class":194},[45,379,208],{"class":181},[45,381,383],{"class":47,"line":382},10,[45,384,385],{"class":181},"    },\n",[45,387,389],{"class":47,"line":388},11,[45,390,391],{"class":181},"  },\n",[45,393,395],{"class":47,"line":394},12,[45,396,215],{"emptyLinePlaceholder":214},[45,398,400,403,405],{"class":47,"line":399},13,[45,401,402],{"class":187},"  rules",[45,404,191],{"class":181},[45,406,182],{"class":181},[45,408,410],{"class":47,"line":409},14,[45,411,412],{"class":221},"    \u002F\u002F 允許的 commit 類型（包含 emoji）\n",[45,414,416,419,423,425,427],{"class":47,"line":415},15,[45,417,418],{"class":133},"    \"",[45,420,422],{"class":421},"sZUrc","type-enum",[45,424,140],{"class":133},[45,426,191],{"class":181},[45,428,429],{"class":194}," [\n",[45,431,433,437],{"class":47,"line":432},16,[45,434,436],{"class":435},"srdBf","      2",[45,438,208],{"class":181},[45,440,442,445,448,450],{"class":47,"line":441},17,[45,443,444],{"class":133},"      \"",[45,446,447],{"class":55},"always",[45,449,140],{"class":133},[45,451,208],{"class":181},[45,453,455],{"class":47,"line":454},18,[45,456,457],{"class":194},"      [\n",[45,459,461,464,466,468],{"class":47,"line":460},19,[45,462,463],{"class":133},"        \"",[45,465,268],{"class":55},[45,467,140],{"class":133},[45,469,208],{"class":181},[45,471,473,475,477,479],{"class":47,"line":472},20,[45,474,463],{"class":133},[45,476,274],{"class":55},[45,478,140],{"class":133},[45,480,208],{"class":181},[45,482,484,486,488,490],{"class":47,"line":483},21,[45,485,463],{"class":133},[45,487,279],{"class":55},[45,489,140],{"class":133},[45,491,208],{"class":181},[45,493,495,497,499,501],{"class":47,"line":494},22,[45,496,463],{"class":133},[45,498,284],{"class":55},[45,500,140],{"class":133},[45,502,208],{"class":181},[45,504,506,508,510,512],{"class":47,"line":505},23,[45,507,463],{"class":133},[45,509,289],{"class":55},[45,511,140],{"class":133},[45,513,208],{"class":181},[45,515,517,519,521,523],{"class":47,"line":516},24,[45,518,463],{"class":133},[45,520,294],{"class":55},[45,522,140],{"class":133},[45,524,208],{"class":181},[45,526,528,530,532,534],{"class":47,"line":527},25,[45,529,463],{"class":133},[45,531,299],{"class":55},[45,533,140],{"class":133},[45,535,208],{"class":181},[45,537,539,541,543,545],{"class":47,"line":538},26,[45,540,463],{"class":133},[45,542,304],{"class":55},[45,544,140],{"class":133},[45,546,208],{"class":181},[45,548,550,552,554,556],{"class":47,"line":549},27,[45,551,463],{"class":133},[45,553,309],{"class":55},[45,555,140],{"class":133},[45,557,208],{"class":181},[45,559,561,563,565,567],{"class":47,"line":560},28,[45,562,463],{"class":133},[45,564,314],{"class":55},[45,566,140],{"class":133},[45,568,208],{"class":181},[45,570,572,574,576,578],{"class":47,"line":571},29,[45,573,463],{"class":133},[45,575,319],{"class":55},[45,577,140],{"class":133},[45,579,208],{"class":181},[45,581,583,585,587,589],{"class":47,"line":582},30,[45,584,463],{"class":133},[45,586,324],{"class":55},[45,588,140],{"class":133},[45,590,208],{"class":181},[45,592,594,597],{"class":47,"line":593},31,[45,595,596],{"class":194},"      ]",[45,598,208],{"class":181},[45,600,602,605],{"class":47,"line":601},32,[45,603,604],{"class":194},"    ]",[45,606,208],{"class":181},[45,608,610],{"class":47,"line":609},33,[45,611,612],{"class":221},"    \u002F\u002F 關閉 type-case 檢查（因為我們的 type 包含 emoji 和空格）\n",[45,614,616,618,621,623,625,627,630,632],{"class":47,"line":615},34,[45,617,418],{"class":133},[45,619,620],{"class":421},"type-case",[45,622,140],{"class":133},[45,624,191],{"class":181},[45,626,195],{"class":194},[45,628,629],{"class":435},"0",[45,631,205],{"class":194},[45,633,208],{"class":181},[45,635,637],{"class":47,"line":636},35,[45,638,639],{"class":221},"    \u002F\u002F 關閉 type-empty 檢查（由 type-enum 處理）\n",[45,641,643,645,648,650,652,654,656,658],{"class":47,"line":642},36,[45,644,418],{"class":133},[45,646,647],{"class":421},"type-empty",[45,649,140],{"class":133},[45,651,191],{"class":181},[45,653,195],{"class":194},[45,655,629],{"class":435},[45,657,205],{"class":194},[45,659,208],{"class":181},[45,661,663],{"class":47,"line":662},37,[45,664,665],{"class":221},"    \u002F\u002F 允許 subject 以小寫或大寫開頭（中文沒有大小寫）\n",[45,667,669,671,674,676,678,680,682,684],{"class":47,"line":668},38,[45,670,418],{"class":133},[45,672,673],{"class":421},"subject-case",[45,675,140],{"class":133},[45,677,191],{"class":181},[45,679,195],{"class":194},[45,681,629],{"class":435},[45,683,205],{"class":194},[45,685,208],{"class":181},[45,687,689],{"class":47,"line":688},39,[45,690,391],{"class":181},[45,692,694],{"class":47,"line":693},40,[45,695,696],{"class":181},"};\n",[20,698,699],{"start":66},[23,700,701,702,705,706,709],{},"透過 Husky 在 ",[42,703,704],{},"commit-msg"," hook 觸發 commitlint，確保每次 ",[42,707,708],{},"git commit"," 時都會套用上述規則：",[35,711,713],{"className":37,"code":712,"language":39,"meta":40,"style":40},"pnpm exec husky add .husky\u002Fcommit-msg \"pnpm exec commitlint --edit $1\"\n",[42,714,715],{"__ignoreMap":40},[45,716,717,719,721,723,725,728,730,733,737],{"class":47,"line":48},[45,718,52],{"class":51},[45,720,81],{"class":55},[45,722,84],{"class":55},[45,724,56],{"class":55},[45,726,727],{"class":55}," .husky\u002Fcommit-msg",[45,729,134],{"class":133},[45,731,732],{"class":55},"pnpm exec commitlint --edit ",[45,734,736],{"class":735},"sfi6f","$1",[45,738,739],{"class":133},"\"\n",[20,741,742],{"start":211},[23,743,744,745,748],{},"若希望提供更友善的錯誤訊息，可將 ",[42,746,747],{},".\u002Fhusky\u002Fcommit-msg"," 檔案內容改成：",[35,750,752],{"className":37,"code":751,"language":39,"meta":40,"style":40},"#!\u002Fbin\u002Fsh\n. \"$(dirname \"$0\")\u002F_\u002Fhusky.sh\"\n\n# 自訂的 commit 訊息驗證\ncommit_msg=$(cat \"$1\")\nif ! echo \"$commit_msg\" | grep -qE '^(✨ feat|🐛 fix|🧹 chore|🔨 refactor|🧪 test|🎨 style|📝 docs|📦 build|👷 ci|⏪ revert|🚀 deploy|🎉 init): .+'; then\n  echo \"提交訊息格式不正確。請使用以下格式之一：\n\n  ✨ feat: 新增功能\n  🐛 fix: 修復錯誤\n  🧹 chore: 修改註解、顯示文字等小異動\n  🔨 refactor: 重構程式碼\n  🧪 test: 新增測試\n  🎨 style: 調整介面或程式碼樣式\n  📝 docs: 更新文件\n  📦 build: 更新建置設定\n  👷 ci: 更新 CI 設定\n  ⏪️ revert: 抵銷更改\n  🚀 deploy: 部署新版本\n  🎉 init: 初始新專案\n\n  範例: ✨ feat: 新增用戶認證功能\n\n  提示: 可使用 VS Code 擴充套件 \\\"Git Commit Plugin with Gitmoji\\\" 快速產生正確格式\"\n  exit 1\nfi\n",[42,753,754,759,782,786,791,814,856,866,870,875,880,885,890,895,900,905,910,915,920,925,930,934,939,943,962,970],{"__ignoreMap":40},[45,755,756],{"class":47,"line":48},[45,757,758],{"class":221},"#!\u002Fbin\u002Fsh\n",[45,760,761,763,766,769,771,774,777,780],{"class":47,"line":66},[45,762,335],{"class":129},[45,764,765],{"class":133}," \"$(",[45,767,768],{"class":51},"dirname",[45,770,134],{"class":133},[45,772,773],{"class":735},"$0",[45,775,776],{"class":133},"\")",[45,778,779],{"class":55},"\u002F_\u002Fhusky.sh",[45,781,739],{"class":133},[45,783,784],{"class":47,"line":211},[45,785,215],{"emptyLinePlaceholder":214},[45,787,788],{"class":47,"line":218},[45,789,790],{"class":221},"# 自訂的 commit 訊息驗證\n",[45,792,793,796,799,802,805,807,809,811],{"class":47,"line":225},[45,794,795],{"class":194},"commit_msg",[45,797,798],{"class":143},"=",[45,800,801],{"class":181},"$(",[45,803,804],{"class":51},"cat",[45,806,134],{"class":133},[45,808,736],{"class":735},[45,810,140],{"class":133},[45,812,813],{"class":181},")\n",[45,815,816,819,822,825,827,830,832,835,838,841,844,847,850,853],{"class":47,"line":235},[45,817,818],{"class":174},"if",[45,820,821],{"class":143}," !",[45,823,824],{"class":129}," echo",[45,826,134],{"class":133},[45,828,829],{"class":194},"$commit_msg",[45,831,140],{"class":133},[45,833,834],{"class":143}," |",[45,836,837],{"class":51}," grep",[45,839,840],{"class":59}," -qE",[45,842,843],{"class":133}," '",[45,845,846],{"class":55},"^(✨ feat|🐛 fix|🧹 chore|🔨 refactor|🧪 test|🎨 style|📝 docs|📦 build|👷 ci|⏪ revert|🚀 deploy|🎉 init): .+",[45,848,849],{"class":133},"'",[45,851,852],{"class":181},";",[45,854,855],{"class":174}," then\n",[45,857,858,861,863],{"class":47,"line":245},[45,859,860],{"class":129},"  echo",[45,862,134],{"class":133},[45,864,865],{"class":55},"提交訊息格式不正確。請使用以下格式之一：\n",[45,867,868],{"class":47,"line":254},[45,869,215],{"emptyLinePlaceholder":214},[45,871,872],{"class":47,"line":351},[45,873,874],{"class":55},"  ✨ feat: 新增功能\n",[45,876,877],{"class":47,"line":382},[45,878,879],{"class":55},"  🐛 fix: 修復錯誤\n",[45,881,882],{"class":47,"line":388},[45,883,884],{"class":55},"  🧹 chore: 修改註解、顯示文字等小異動\n",[45,886,887],{"class":47,"line":394},[45,888,889],{"class":55},"  🔨 refactor: 重構程式碼\n",[45,891,892],{"class":47,"line":399},[45,893,894],{"class":55},"  🧪 test: 新增測試\n",[45,896,897],{"class":47,"line":409},[45,898,899],{"class":55},"  🎨 style: 調整介面或程式碼樣式\n",[45,901,902],{"class":47,"line":415},[45,903,904],{"class":55},"  📝 docs: 更新文件\n",[45,906,907],{"class":47,"line":432},[45,908,909],{"class":55},"  📦 build: 更新建置設定\n",[45,911,912],{"class":47,"line":441},[45,913,914],{"class":55},"  👷 ci: 更新 CI 設定\n",[45,916,917],{"class":47,"line":454},[45,918,919],{"class":55},"  ⏪️ revert: 抵銷更改\n",[45,921,922],{"class":47,"line":460},[45,923,924],{"class":55},"  🚀 deploy: 部署新版本\n",[45,926,927],{"class":47,"line":472},[45,928,929],{"class":55},"  🎉 init: 初始新專案\n",[45,931,932],{"class":47,"line":483},[45,933,215],{"emptyLinePlaceholder":214},[45,935,936],{"class":47,"line":494},[45,937,938],{"class":55},"  範例: ✨ feat: 新增用戶認證功能\n",[45,940,941],{"class":47,"line":505},[45,942,215],{"emptyLinePlaceholder":214},[45,944,945,948,952,955,957,960],{"class":47,"line":516},[45,946,947],{"class":55},"  提示: 可使用 VS Code 擴充套件 ",[45,949,951],{"class":950},"s_hVV","\\\"",[45,953,954],{"class":55},"Git Commit Plugin with Gitmoji",[45,956,951],{"class":950},[45,958,959],{"class":55}," 快速產生正確格式",[45,961,739],{"class":133},[45,963,964,967],{"class":47,"line":527},[45,965,966],{"class":129},"  exit",[45,968,969],{"class":435}," 1\n",[45,971,972],{"class":47,"line":538},[45,973,974],{"class":174},"fi\n",[15,976,978],{"id":977},"使用-lint-staged-在-commit-前自動檢查檔案","使用 lint-staged 在 commit 前自動檢查檔案",[11,980,981],{},"除了檢查 commit 訊息外，也可以在提交前自動檢查程式碼品質，確保程式碼狀態良好再進入版本庫。",[20,983,984],{},[23,985,986,987,992],{},"安裝 ",[27,988,991],{"href":989,"rel":990},"https:\u002F\u002Fgithub.com\u002Flint-staged\u002Flint-staged",[31],"lint-staged","：",[35,994,996],{"className":37,"code":995,"language":39,"meta":40,"style":40},"pnpm add --save-dev lint-staged\n",[42,997,998],{"__ignoreMap":40},[45,999,1000,1002,1004,1006],{"class":47,"line":48},[45,1001,52],{"class":51},[45,1003,56],{"class":55},[45,1005,60],{"class":59},[45,1007,1008],{"class":55}," lint-staged\n",[20,1010,1011],{"start":66},[23,1012,1013,1014,1017],{},"新增 ",[42,1015,1016],{},"lint-staged.config.js"," 檔案，根據專案需求設定要執行的檢查。例如以下會在提交前針對 TS\u002FJS 進行 ESLint、針對 CSS\u002FSCSS 進行 Stylelint，再由 Prettier 格式化所有支援的檔案：",[35,1019,1021],{"className":165,"code":1020,"language":167,"meta":40,"style":40},"export default {\n  \"*.{ts,tsx,js,jsx,vue}\": [\"pnpm lint\"],\n  \"*.{css,scss}\": [\"pnpm stylelint\"],\n  \"*\": [\"pnpm format\"],\n};\n",[42,1022,1023,1031,1056,1080,1104],{"__ignoreMap":40},[45,1024,1025,1027,1029],{"class":47,"line":48},[45,1026,175],{"class":174},[45,1028,178],{"class":174},[45,1030,182],{"class":181},[45,1032,1033,1036,1039,1041,1043,1045,1047,1050,1052,1054],{"class":47,"line":66},[45,1034,1035],{"class":133},"  \"",[45,1037,1038],{"class":421},"*.{ts,tsx,js,jsx,vue}",[45,1040,140],{"class":133},[45,1042,191],{"class":181},[45,1044,195],{"class":194},[45,1046,140],{"class":133},[45,1048,1049],{"class":55},"pnpm lint",[45,1051,140],{"class":133},[45,1053,205],{"class":194},[45,1055,208],{"class":181},[45,1057,1058,1060,1063,1065,1067,1069,1071,1074,1076,1078],{"class":47,"line":211},[45,1059,1035],{"class":133},[45,1061,1062],{"class":421},"*.{css,scss}",[45,1064,140],{"class":133},[45,1066,191],{"class":181},[45,1068,195],{"class":194},[45,1070,140],{"class":133},[45,1072,1073],{"class":55},"pnpm stylelint",[45,1075,140],{"class":133},[45,1077,205],{"class":194},[45,1079,208],{"class":181},[45,1081,1082,1084,1087,1089,1091,1093,1095,1098,1100,1102],{"class":47,"line":218},[45,1083,1035],{"class":133},[45,1085,1086],{"class":421},"*",[45,1088,140],{"class":133},[45,1090,191],{"class":181},[45,1092,195],{"class":194},[45,1094,140],{"class":133},[45,1096,1097],{"class":55},"pnpm format",[45,1099,140],{"class":133},[45,1101,205],{"class":194},[45,1103,208],{"class":181},[45,1105,1106],{"class":47,"line":225},[45,1107,696],{"class":181},[20,1109,1110],{"start":211},[23,1111,1013,1112,1115,1116,1118],{},[42,1113,1114],{},".\u002Fhusky\u002Fpre-commit"," 檔案，讓 Husky 在 ",[42,1117,708],{}," 時只對 staged 檔案執行上述檢查：",[35,1120,1122],{"className":37,"code":1121,"language":39,"meta":40,"style":40},"#!\u002Fbin\u002Fsh\n. \"$(dirname \"$0\")\u002F_\u002Fhusky.sh\"\n\npnpm exec lint-staged\n",[42,1123,1124,1128,1146,1150],{"__ignoreMap":40},[45,1125,1126],{"class":47,"line":48},[45,1127,758],{"class":221},[45,1129,1130,1132,1134,1136,1138,1140,1142,1144],{"class":47,"line":66},[45,1131,335],{"class":129},[45,1133,765],{"class":133},[45,1135,768],{"class":51},[45,1137,134],{"class":133},[45,1139,773],{"class":735},[45,1141,776],{"class":133},[45,1143,779],{"class":55},[45,1145,739],{"class":133},[45,1147,1148],{"class":47,"line":211},[45,1149,215],{"emptyLinePlaceholder":214},[45,1151,1152,1154,1156],{"class":47,"line":218},[45,1153,52],{"class":51},[45,1155,81],{"class":55},[45,1157,1008],{"class":55},[11,1159,1160,1161,1164,1165,1167],{},"若檢查失敗，commit 會被取消並提示錯誤；修正後重新 ",[42,1162,1163],{},"git add","、",[42,1166,708],{}," 即可。",[15,1169,1171],{"id":1170},"針對-branch-名稱的格式檢查","針對 branch 名稱的格式檢查",[1173,1174,1175],"ul",{},[23,1176,1177],{},"在 git push 前針對 branch 名稱的格式檢查，以 pnpm 為例：",[11,1179,1180],{},"建立 .\u002Fhusky\u002Fpre-push 檔案，內容如下：",[35,1182,1184],{"className":37,"code":1183,"language":39,"meta":40,"style":40},"#!\u002Fbin\u002Fsh\n\nbranch_name=$(git symbolic-ref --short HEAD)\nregex='^(feat|fix|chore|refactor|test|style|docs|build|ci|revert|deploy|init)\\\u002F.*$'\n\nif [ \"$branch_name\" = \"main\" ]; then\n  exit 0\nfi\n\necho \"當前分支名稱：$branch_name\"\nif ! echo \"$branch_name\" | grep -qE \"$regex\"; then\n  echo \"🚨 分支名稱格式錯誤，請使用 type\u002Ftitle 格式\"\n  echo \"可用的 type: feat, fix, chore, refactor, test, style, docs, build, ci, revert, deploy, init\"\n  echo \"範例: feat\u002Fadd-login-page\"\n  exit 1\nfi\n",[42,1185,1186,1190,1194,1217,1232,1236,1264,1271,1275,1279,1292,1323,1334,1345,1356,1362],{"__ignoreMap":40},[45,1187,1188],{"class":47,"line":48},[45,1189,758],{"class":221},[45,1191,1192],{"class":47,"line":66},[45,1193,215],{"emptyLinePlaceholder":214},[45,1195,1196,1199,1201,1203,1206,1209,1212,1215],{"class":47,"line":211},[45,1197,1198],{"class":194},"branch_name",[45,1200,798],{"class":143},[45,1202,801],{"class":181},[45,1204,1205],{"class":51},"git",[45,1207,1208],{"class":55}," symbolic-ref",[45,1210,1211],{"class":59}," --short",[45,1213,1214],{"class":55}," HEAD",[45,1216,813],{"class":181},[45,1218,1219,1222,1224,1226,1229],{"class":47,"line":218},[45,1220,1221],{"class":194},"regex",[45,1223,798],{"class":143},[45,1225,849],{"class":133},[45,1227,1228],{"class":55},"^(feat|fix|chore|refactor|test|style|docs|build|ci|revert|deploy|init)\\\u002F.*$",[45,1230,1231],{"class":133},"'\n",[45,1233,1234],{"class":47,"line":225},[45,1235,215],{"emptyLinePlaceholder":214},[45,1237,1238,1240,1242,1244,1247,1249,1252,1254,1257,1259,1262],{"class":47,"line":235},[45,1239,818],{"class":174},[45,1241,195],{"class":181},[45,1243,134],{"class":133},[45,1245,1246],{"class":194},"$branch_name",[45,1248,140],{"class":133},[45,1250,1251],{"class":143}," =",[45,1253,134],{"class":133},[45,1255,1256],{"class":55},"main",[45,1258,140],{"class":133},[45,1260,1261],{"class":181}," ];",[45,1263,855],{"class":174},[45,1265,1266,1268],{"class":47,"line":245},[45,1267,966],{"class":129},[45,1269,1270],{"class":435}," 0\n",[45,1272,1273],{"class":47,"line":254},[45,1274,974],{"class":174},[45,1276,1277],{"class":47,"line":351},[45,1278,215],{"emptyLinePlaceholder":214},[45,1280,1281,1283,1285,1288,1290],{"class":47,"line":382},[45,1282,130],{"class":129},[45,1284,134],{"class":133},[45,1286,1287],{"class":55},"當前分支名稱：",[45,1289,1246],{"class":194},[45,1291,739],{"class":133},[45,1293,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312,1314,1317,1319,1321],{"class":47,"line":388},[45,1295,818],{"class":174},[45,1297,821],{"class":143},[45,1299,824],{"class":129},[45,1301,134],{"class":133},[45,1303,1246],{"class":194},[45,1305,140],{"class":133},[45,1307,834],{"class":143},[45,1309,837],{"class":51},[45,1311,840],{"class":59},[45,1313,134],{"class":133},[45,1315,1316],{"class":194},"$regex",[45,1318,140],{"class":133},[45,1320,852],{"class":181},[45,1322,855],{"class":174},[45,1324,1325,1327,1329,1332],{"class":47,"line":394},[45,1326,860],{"class":129},[45,1328,134],{"class":133},[45,1330,1331],{"class":55},"🚨 分支名稱格式錯誤，請使用 type\u002Ftitle 格式",[45,1333,739],{"class":133},[45,1335,1336,1338,1340,1343],{"class":47,"line":399},[45,1337,860],{"class":129},[45,1339,134],{"class":133},[45,1341,1342],{"class":55},"可用的 type: feat, fix, chore, refactor, test, style, docs, build, ci, revert, deploy, init",[45,1344,739],{"class":133},[45,1346,1347,1349,1351,1354],{"class":47,"line":409},[45,1348,860],{"class":129},[45,1350,134],{"class":133},[45,1352,1353],{"class":55},"範例: feat\u002Fadd-login-page",[45,1355,739],{"class":133},[45,1357,1358,1360],{"class":47,"line":415},[45,1359,966],{"class":129},[45,1361,969],{"class":435},[45,1363,1364],{"class":47,"line":432},[45,1365,974],{"class":174},[1367,1368,1369],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .s-KJb, html code.shiki .s-KJb{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#DBEDFF}html pre.shiki code .sQRbd, html code.shiki .sQRbd{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#DBEDFF}html pre.shiki code .sZUrc, html code.shiki .sZUrc{--shiki-light:#E53935;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sfi6f, html code.shiki .sfi6f{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":40,"searchDepth":211,"depth":211,"links":1371},[1372,1373,1374,1375,1376],{"id":17,"depth":66,"text":18},{"id":90,"depth":66,"text":91},{"id":150,"depth":66,"text":151},{"id":977,"depth":66,"text":978},{"id":1170,"depth":66,"text":1171},"Git","2025-01-22","使用 husky 與 commitlint 來自動檢查 commit 訊息跟 branch 名稱的格式",false,"md",null,{},"\u002Fblog\u002Fgit\u002Fhusky-and-commitlint",{"title":5,"description":1379},"blog\u002Fgit\u002Fhusky-and-commitlint",[1377],"2025-11-10","Tn5OZ-Ij3EImCsUVNRu8-vD0ISqMmk_f_ZvRPCrjVTw",1780512500691]