چگونه یک پیغام git commit با معنا بنویسیم؟

در قسمت قبل شهاب ما رو با گیت آشنا کرد و فهمیدیم که گیت چیه؟ در این قسمت به اعماق کامیت ها در گیت میریم و خواهید دید که گیت چقدر هیجان انگیز هست!

نوشتن کامیت خوب یک هنر است! و این زمانی بیشتر خودشو نشون میده که در یک تیم مشغول به کار باشید یا اینکه بخواهید یک مروری بر آنچه که قبلا در پروژه انجام داده اید داشته باشید. خیلی وقتها می خواهیم با نوشتن یک پیغام نامفهوم یک کامیتی زده باشیم! ولی خب اگر بخواهید روی یک پروژه متن باز مشارکت کنید چی؟ یا اینکه درون یک تیم مشغول به کار باشید؟

اندرحکایت نوشتن متن کامیت های گیت!
اندرحکایت نوشتن متن کامیت های گیت!

قدرت گیت در کارهای تیمی بسیار مشخص تر خواهد بود. رعایت کردن یکسری استاندارد بین افراد یک پروژه می تواند روند کارها را سریعتر و اشتباهات را کاهش دهد. یکی از این استانداردها می تواند تدوین قوانینی برای نوشتن توضیحات برای Commitها در گیت باشد. [^]

در ادامه نوشته منظور از "کامیت (commit) با معنا" در واقع پیغام کامیت می باشد.

? هدف از نوشتن commit  با معنا

  • تولید خودکار فایل CHANGELOG.md توسط اسکریپت
  • در نظر نگرفتن بعضی از کامیت های بی اهمیت با git bisect (مانند مثل فورمت کردن کدها)
  • داشتن اطلاعات بهتر و کاراتر هنگام بازببینی تاریخچه کامیت ها

تولید خودکار فایل CHANGELOG.md توسط اسکریپت

فایلی است مارک داون که ما تغییرات هر نسخه منتشر شده (release) رو اونجا می نویسیم (مثال). و عمدتا سه قسمت داره: امکانات (features) جدید، رفع اشکال (bug) و تغییرات ایجاد شده (breaking changes).

که می توان اینها را توسط یک اسکریپت به شکل خودکار تولید کرد و لینک کامیت مربوطه هم کنار آن درج کنیم.

پرواضح است که خودمان نیز می توانیم فایل را تغییر دهیم اما می توان از اسکریپت برای تولید پایه و اساس فایل changelog بهره برد.

برای مثال دستور زیر لیستی از تمام موضوعات (خط اول هر پیغام کامیت) از اخرین انتشار (release)

git log <last tag> HEAD --pretty=format:%s

امکانات جدید نسخه جاری

git log <last release> HEAD --grep feature

شناخت کامیت های کم اهمیت

تغییراتی مانند فورمت کردن کد (اضافه/ حذف space ها، خط های خالی و فاصله گذاری indentation) یا فراموش کردن semi colon ها و نوشتن کامنت. پس زمانی که شما برای یک تغییر می گردید می توانید این کامیت ها را در نظر نگیرید. کامیتی است که منطق برنامه در آن عوض نمی شود.

وقتی از bisect استفاده می کنید، می توان از دستور زیر استفاده کرد

(git bisect skip $(git rev-list --grep irrelevant <good place> HEAD

داشتن اطلاعات بهتر و کاراتر هنگام بازببینی تاریخچه کامیت ها

کامیت های خوب تا حدی اطلاعات پایه ای را برایمان فراهم می کنند. برای مثال نگاهی به آخرین کامیت ها انگولار می اندازیم.

همین این پیام ها به نحوی مشخص می کند که تغییر کجا اتفاق افتاده است. اما هیچ قاعده (convention) مشترکی بین آنها دیده نمی شود. حال به این پیام (کامیت) ها نگاهی بیندازید:

آیا می توانید حدس بزنید که چه اتفاقی درون کدها افتاده است؟ این پیام ها محل انجام تغییرات را ذکر نکرده است. ممکن است تغییرات در قسمت هایی از کد از جمله (مستندات پروژه، کامپایلر و ...): docsdocs-parsercompilerscenario-runner, …

بله ما هم می دانیم که به راحتی می توان تغییرات انجام شده را با بررسی فایل ها تغییر یافته اطلاعات لازم را بدست آورد، اما این روندی کند است.  و البته با نگاهی به تاریخچه گیت (git log) می توان با کمی تلاش محل تغییرات را فهمید ولی باز از قاعده خاصی پیرو نمی کنند.

? قراردادی برای بهتر نوشتن  پیام کامیت ها

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

برای مثال:

fix(middleware): ensure Range headers adhere more closely to RFC 2616

Add one new dependency, use `range-parser` (Express dependency) to compute
range. It is more well-tested in the wild.

Fixes #2310

هر خط از پیغام کامیت نباید بیشتر از 100 کاراکتر باشد. همین باعث می شود که خواندن متن کامیت هم در گیتهاب و هم در سایر ابزار های گیت آسان تر باشد. هر متن کامیت دارای سرآمد (header)، بدنه (body) و بخش زیرین (footer) است که توسط خط خالی (Blank line) از هم جدا می شود.

 متن سرآمد

متن قسمت سرآمدیک خط است که به صورت خلاصه وارتوضیحاتی را در مورد تغییرات ارایه میدهد و شامل نوع (typeمحدوده [تغییرات] (scope) و موضوع (subject) می باشد.

مقادیر مجاز  <type>

نوع تغییرات که کامیت شده را بیان می کند:

  •   افزودن یک ویژگی جدید به پروژه (feat (feature
  •    حل یک مشکل (fix (bug fix
  •  مستندات پروژه (docs (documentation
  •  فورمت کردن کد (...,style (formatting, missing semi colons
  •  refactor
  •  آزمون واحد و یکپارچه سازی (test (when adding missing tests
  •  کارهایی از قبیل اضافه کردن تسک های gulp و npm و... که تغییری در فایل های آزمون و src ایجاد نمی کنیم ?.(chore (maintain

مقادیر مجاز <scope>

محدوده هر چیزی می تواند باشد که محل انجام تغییرات را بیان می کند که در آن کامیت تغییر یافته اند. برای مثال: login, نام کامپوننت ، middleware، ... یا اگر محل مناسبی را برای تغییرات انجام شده نیافتید * می گذاریم.

متن <subject>

یک توضیح بسیار کوتاه در مورد تغییر انجام شده.

  1. از یک فعل امری و زمان حال استفاده کنید: برای مثال "change" و نه "changed" یا "changes"
  2. اولین حرف را بزرگ نمی نویسیم.
  3. اخر جمله . نمی گذاریم.

متن بدنه <body>

  • همانند متن موضوع از یک فعل امری و زمان حال استفاده کنید: برای مثال "change" و نه "changed" یا "changes"
  • دربرگیرنده انگیزه برای تغییر و بیان تفاوت با رفتار قبلی

[ +, + ]

متن بخش زیرین <footer>

تغییرات ایجاد شده ‌‌Breaking changes

تمامی تغییرات ایجاد شده باید در قسمت ‌Breaking changes فوتر آورده شود، که باید با کلمه BREAKING CHANGE با یک فاضله  یا دو خط جدید. مابقی متن کامیت توضیحی است در مورد تغییرات و نکاتی برای توجیه و ارتقا به تغییرات جدید.

BREAKING CHANGE: isolate scope bindings definition has changed and
    the inject option for the directive controller injection was removed.
   
    To migrate the code follow the example below:
   
    Before:
   
    ...

    After:
   
    ....
   
    The removed `inject` wasn't generaly useful for directives so there should be no code using it.

ارجاع دادن به یک issue

اشکالات رفع شده (یا ایشو های بسته شده) باید در یک خط جداگانه در فوتر با پیشوند "Closes" نوشته شود.

Closes #234

یا چندین مورد را به این شکل می نویسیم:

Closes #123, #245, #992

مثال ها

feat($browser): onUrlChange event (popstate/hashchange/polling)
Added new event to $browser:
- forward popstate event if available
- forward hashchange event if popstate not available
- do polling when neither popstate nor hashchange available
Breaks $browser.onHashChange, which was removed (use onUrlChange instead)

fix($compile): couple of unit tests for IE9

Older IEs serialize html uppercased, but IE9 does not...

Would be better to expect case insensitive, unfortunately jasmine does

not allow to user regexps for throw expectations.

Closes #392

Breaks foo.bar api, foo.baz should be used instead

کامیت های معنی دار در عمل

برای اینکه مطلب گفته شده روشن تر شود اجازه دهید که ابزار های لازم را برای این کار معرفی کنیم تا روند کار آسان تر و لذت بخش تر شود. برای این منظور مخزن بوت استرپ 4 راستچین را به نسخه بتا (آزمایش عمومی) به روزرسانی می کنیم.

قدم 1 : دانلود commitizen

اگر درون پروژه خود فایل package.json دارید کافیه است. با دستور زیر از طریق ترمینال بسته های لازم را دانلود کنید.

npm install -D commitizen cz-conventional-changelog

و سپس درون فایل package.json دو قسمت زیر را اضافه می کنیم.

"scripts": {
    ...
    "commit": "git-cz"
  }

.
.
.

,
  "config": {
    "commitizen": {
      "path": "node_modules/cz-conventional-changelog"
    }
  }

و همچنین کد زیر را به فایل README.md اضافه می کنیم (کاملا اختیاری)

[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)

حال با دستور git add فایل های مورد نظر را انتخاب می کنیم. و سپس دستور  npm run commit رو می زنیم. سوالاتی را از ما می پرسد. که طبق مطالب اریه شده به راحتی می توان متن مناسب را بنویسیم.

سوالات کامیتیزن برای ثبت کامیت جدید
سوالات کامیتیزن برای ثبت کامیت جدید

به همین راحتی! حتی ایشو شماره 4 که باز کرده بودم را اتومات می بنده!

بسته شدن خودکار ایشو شماره چهار !
بسته شدن خودکار ایشو شماره چهار !

خوشحال می شویم مثل همیشه پیشنهادی، سوالی دارید؟ بپرسید

منابع: + ++