輕鬆上手約定式提交:Commitizen 初體驗

最近參加 DevOps Meetup 的活動,Speaker 提到團隊使用 Commitizen 這套工具來統一提交訊息的風格,當場就有種醍醐灌頂的感覺。我們團隊前陣子才 Suffer 在 Commit Style 分歧,知識管理效率低落,有時只有 commit 本人能看懂,而使用共同模板又太浪費時間,跟 Git 鼓勵 commit 的精神背道而馳。聽完後,真的是相見恨晚,完全命中我的痛點。

Commitizen 是由 AngularJS 的規範衍伸而來,各團隊可以依照需求自行調整,我們 Step by Step 來看看 Commitizen 的效果如何。

Install Node.js

因為 Commitizen 是使用 Node.js 開發,不免俗的,要裝一下 Node.js,Ubuntu 的安裝方式是

sudo apt install nodejs
sudo apt install npm

確認是否有安裝完成

ken@ken-Lenovo-ideapad-330-15ICH:~/git/git$ node -v
v8.10.0
ken@ken-Lenovo-ideapad-330-15ICH:~/git/git$ npm -v
3.5.2

Install Commitizen

接著使用 Node.js 的 Package Management 工具 npm 來安裝 Commitizen

npm install -g commitizen
echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc

-g 是全域安裝的意思,如果沒有需要針對 Project 制定 Style,用全域安裝即可,.czrc 則是用來設定 template 的路徑。

Git Format

在預設的 format 中,commit comment 由三個部分組成

<head>
<body>
<footer>

讓我們看一個簡單的例子

commit 4030e040b6044de68b2750702a5b6065c887960c
Author: kenwschen <ken*****@[gmail.com](mailto:[email protected])>
Date:   Thu Nov 28 22:51:44 2019 +0800

feat(libhello): add hello file

hello, this is a longer description

fix #100

第一行是 head,也就是 title,通常會由

<type>(<scope>): <subject>

在本例中可以看成這個 commit 為新增功能(feature),更改的 module 是 libhello,簡單描述是 add hello file。

中間行是 body,代表詳細的描述,通常會說明要解決的問題是什麼,具體做法是什麼等等。

最後一行是 footer,通常會標明相關的 issue,如果沒有將 issue 跟 git 結合在一起的話,footer 可以不標。

Git cz

實際執行 Commitizen,使用 git cz 來取代 git commit

可以看到,Commitizen 會很貼心顯示選單讓 user 選擇,只要照著問題跟選單將答案填入就好,就是這麼簡單。

來看一下提交的結果

ken@ken-Lenovo-ideapad-330-15ICH:~/git$ echo hello > hello     
ken@ken-Lenovo-ideapad-330-15ICH:~/git$ git add .              
ken@ken-Lenovo-ideapad-330-15ICH:~/git$ git cz                 
[email protected], [email protected]                  
                                                                
? Select the type of change that you're committing: feat:        A new feature                                                     
? What is the scope of this change (e.g. component or file name): (press enter to skip) libhello                                   
? Write a short, imperative tense description of the change (max 84 chars):                                                        
    (14) add hello file                                               
? Provide a longer description of the change: (press enter to skip)
    hello, this is a longer description
? Are there any breaking changes? No
? Does this change affect any open issues? No
[master 2e1ea38] feat(libhello): add hello file
    1 file changed, 1 insertion(+)
    create mode 100644 hello

ken@ken-Lenovo-ideapad-330-15ICH:~/git$ git log
commit 2e1ea3868dcf972c2499378ee9d5b3ac7ab654b6 (HEAD -> master)
Author: kenwschen <[ken*****@gmail.com](mailto:[email protected])>
Date:   Fri Nov 29 00:40:31 2019 +0800

feat(libhello): add hello file

hello, this is a longer description

是不是太美了!

Customize Format

如果專案有自訂格式,例如需要標註修改方式、修改目的等等,可以怎麼做?Commitizen 支援許多模板,其中 cz-customizable 有讓 user 自訂選項的彈性,先安裝起來

sudo npm install -g cz-customizable
echo '{ "path": "cz-customizable" }' > ~/.czrc

將配置項的範例複製到家目錄

cp /usr/local/lib/node_modules/cz-customizable/cz-config-EXAMPLE.js ~/.cz-config.js

打開配置文件,可以看到其中有許多配置設定,假設現在需要新增一個互動問答,讓 user 輸入 commit 的 purpose,可以在其中加入

    messages: {
        type: "Select the type of change that you're committing:",
        scope: '\nDenote the SCOPE of this change (optional):',
        customScope: 'Denote the SCOPE of this change:',
        subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
        body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
        **bodyPurpose: 'The purpose of the change:\n',**
        breaking: 'List any BREAKING CHANGES (optional):\n',
        footer: 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
        confirmCommit: 'Are you sure you want to proceed with the commit above?',
      },

其中 bodyPurpose 這行是新加入的選項。

接著修改問句文件

sudo vi /usr/local/lib/node_modules/cz-customizable/questions.js

在其中加入 bodyPurpose

    ...
    messages.body =
          messages.body || 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n';
        **messages.bodyPurpose = messages.bodyPurpose || 'The purpose of the change:\n';**
        messages.breaking = messages.breaking || 'List any BREAKING CHANGES (optional):\n';
    ...

    ...
          {
            type: 'input',
            name: 'body',
            message: messages.body,
          },
          **{
            type: 'input',
            name: 'bodyPurpose',
            message: messages.bodyPurpose,
          },**
    ...

然後修改 commit 生成文件,將 bodyPurpose 加入

    let body = wrap(answers.body, wrapOptions) || '';
    **body = body + (wrap(answers.bodyPurpose, wrapOptions) || '');**
    body = addBreaklinesIfNeeded(body, config.breaklineChar);

現在來看一下修改的成果

而實際的 log 是

commit 3cc8c9aa4a9084fb4b8faa651d98b5376f24e4d6 (HEAD -> master)
Author: kenwschen <[[email protected]](mailto:[email protected])>
Date:   Fri Nov 29 19:56:58 2019 +0800

feat(libhello): add hello file

add a new file to test commitizen tool. hello is a lib that can say "hello"

小結

有時候程式寫一寫,會忘記升級自己的工具,很多時候團隊遇到的問題不是人的問題,而是工具的問題,我們應該要盡量 align 目標,用工具時時提醒出發點在哪。commit comment 原本是為了溝通而存在,而 Commitizen 可以幫我們更好地去做這件事。

Reference

Read more

Weekly Issue 第 9 期:Ghost 發布 6.0 版本

Ghost Release 新版了!距離上次大版號更新,已經過了 3 年多,這幾年來,創作者經濟變化得很快,Ghost 也嘗試讓創作者更容易經營自己的內容。 我會等 6.0 發布一陣子,穩定下來後才會更新。很期待他們下一步會是什麼。 🗞️ 熱門新聞 Ghost 6.0 Ghost Release 6.0。 兩個重量級更新:支援 ActivityPub,讓 Ghost 可以 Leverage 社群媒體分發渠道;以及內建 Analytics,支援流量分析。這剛好就是兩個我最想要的功能,Great Work。 常說經營內容的痛點在,不知道如何發佈內容,不知道訪客從哪來。當然這都可以用工具協助,例如設定 GA、或者使用 Postiz 等來經營社群,可是我覺得一個好的平台應該要替創作者處理掉這些事,Ghost

By Ken Chen

Weekly Issue 第 8 期:數位時代的遷徙自由

以前在開發內容平台產品時,常常想,如果有天我們的使用者要離開平台,他們擁有自由嗎?在現代,數位創作者有點像是佃農,替平台生產內容,可是因為數位落差,他們沒有移動的能力。 隨著時代進步,法規應該要與時俱進,這期選了數位部的公告草案,告訴我們科技與制度可以如何相輔相成。 另外,從本期開始,加入了目錄大綱,希望讓讀者閱讀時能更容易在不同議題間切換。 🗞️ 熱門新聞 社交資料可攜權與互通性 在唐鳳那看到這則消息,最近衛城出版編輯的帳號被無預警停權,引發討論,我自己也常常焦慮,當使用這些便利的平台服務時,我們是不是交出一些沒意識到的權利? 身為個人,可行的策略是,在發布內容到平台前,先保留一份在自己手中,但這其中的不平等顯而易見。《數位選擇法案》讓我理解到,創作者有機會在一個更好更平等的環境下創作。 我希望台灣也能有這樣的一天。 I gave the AI arms and legs – then it rejected me 在 HN 上看到的新聞,有名開發者發現自己的函式庫被用在 Claude

By Ken Chen

Weekly Issue 第 7 期:從 GitHub Spark 看 Prompt 工程

近期開始有人建議用 Context Engineering 來取代 Prompt Engineering,的確相較於 Prompt,Context 是更精確的用詞。前一期也提到,當 Duolingo 的 CEO 被問到 AI 是否只是模型套皮時,他也說模型一定有影響,但更多是關乎你的 Context。 那麼,業界現在是如何看待 Prompt 的呢?Github Spark 跟 V0 的例子或許能提供一些參考。 🗞️ 熱門新聞 Using GitHub Spark to reverse engineer GitHub Spark GitHub Spark 最近推出公開預覽,讓你可以用 prompt 直接開發應用。 作者用逆向工程,找出 Spark 的 system

By Ken Chen

Weekly Issue 第 6 期:Duolingo CEO 看 AI 與遊戲化

現在是 AI 時代,大家都在想怎麼讓自己的產品跟 AI 掛勾,但具體要怎麼做呢?背後的思考有哪些?Duolingo 給出他們自己的觀點。 例如,現在的產品是否只是 AI 套皮,你接收使用者的問題,套上自己的提詞後,拿去給 OpenAI,要它回答你?在現在百家爭鳴的情況下,選擇哪個模型會有差嗎?AI 能帶來新用戶與新營收嗎?等等。 另外本週也選了一篇少數派的文章,談 AI 對 RSS 的影響,對 RSS 未來方向有興趣的人不妨看看。 🗞️ 熱門新聞 Duolingo CEO Luis von Ahn wants you addicted to learning Duolingo CEO 專訪,相當紮實,推薦閱讀。 「對我們來說,

By Ken Chen