برنامه نویسی

آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

در این پست قصد داریم تا ابزار محبوب سیستم کنترل ورژن، Git و اصول استفاده از آن را بیان کنیم. اکثر ما به شرایطی برخوده ایم که نیاز به دانستن تاریخچه تغییرات داشته ایم تا بتوانیم به راحتی پروسه و گام های خود را بررسی کنیم یا تغییراتی را به عقب بازگردانیم. داشتن تغییرات در کارهای گروهی نیز دارای اهمیت بسیاری است.

با اینکه ابزار Git بیشتر از همه چیز در توسعه کد استفاده شده اما نباید از این نکته غافل شد که این ابزار برای مدیریت ورژن *فایل ها* ساخته شده است و نه تنها کد، بلکه هر فایلی حتی عکس را نیز میتوان ورژن بندی کرد.

امروزه ابزار Git برای توسعه دهندگان و برنامه نویسان ضرورت بسیاری دارد. ورژن بندی نرم افزار دارای اهمیت زیادی است چرا که در مدیریت روند توسعه نرم افزار تأثیر مستقیمی می گذارد. اگر در پیشنهادات کار برنامه نویسی نگاه کنید همیشه بلد بودن Git یکی از نیازمندی ها است.

ابزار Git چیست؟

همانطور که در بالا گفته شد ابزار Git یک ابزار کنترل ورژن فایل ها است. اما نکته دیگری که وجود دارد غیر متمرکز بودن این ابزار است. در ابزارهای دیگر، تمامی تغییرات در یک سرور مرکزی نگهداری می شود اما در Git، شما تمامی تغییرات را در تمام کپی های repository خواهید داشت. با این حساب هم یک بکاپ در مخزن محلی یعنی در سیستم افراد تیم قرار خواهد داشت و هم دیگر نیازی به یک سرور مرکزی نیست. هرچند که داشتن یک سرور مرکزی برای اشتراک اطلاعات معمولا نیاز است تا کار را تسریع و هماهنگی را تضمین کند.

ابزار git قابلیت های زیر را در اختیار شما می گذارد:

  • نگهداری تغییرات به همراه توضیح و ثبت کننده آن
  • بازگردانی به هر نقطه از تغییرات تنها با یک دستور
  • شاخه بندی کد برای توسعه موازی
  • ادغام دو شاخه در صورت نیاز
  • جلوگیری از تداخل ادغام یا همان merge conflict
  • نام گذاری با استفاده از tag برای یک تغییر برای دسترسی آسانتر
  • مشاهده تغییرات فایل ها در ورژن های مختلف آنها با فرمتی مناسب
  • تولید لاگ متنی از تغییرات که میتوان از آن در ابزارهای دیگر استفاده کرد مانند تولید CHANGELOG بصورت اتوماتیک

برنامه git برای اولین بار در سال ۲۰۰۵ توسط Linus Torvalds ساخته شد و در همان سال وظیفه توسعه و نگهداری آن به Junio Hamano انتقال یافت.

اجزا و اشیاء مختلف Git

برنامه Git چند جزء اساسی دارد که کاربر آن باید بداند و همچنین چند نوع شیء داخلی دارد که دانستن آنها بد نیست.

اجزا از دید کاربر:

  • Files: فایلها قسمتی هستند که اساسا به خود Git ربطی ندارند اما فایل هایی که در زیر پوشه .git وجود دارند کاملا مربوط به git بوده و کاربر نباید آنها را ویرایش کند. برنامه Git بر اساس فایل هایی که در پوشه .git وجود دارد فایل های شما را ادیت می کند.
  • Commit: در هر تاریخی تنها نقاطی از آن ثبت و ضبط می شوند و در Git نیز همینطور است. در Git تاریخچه از Commit ها تشکیل شده که هر Commit مانند یک گره یا نقطه می ماند که تغییرات در فایلها، کاربر تغییر دهنده و پیامی از سوی تغییر دهنده به همراه دیگر meta داده ها نگه می دارد. به هر Commit در پروژه یک Hash Code اختصاص می یابد که با استفاده از آنها میتوانید به Commit خاصی اشاره کنید. با استفاده از این اطلاعات ثبت شده در هر Commit برنامه Git به شما اجازه می دهد که تغییرات را بازگردانی کنید و به آن حالتی که Commit در آن موقع ثبت شد باز گردید.
  • Branch: شاخه بندی برای مواقعیست که میخواهیم تغییرات را در یک کپسوله ای جدا و یا به صورت موازی انجام دهیم و خطوط توسعه بخش ها را از هم جدا کنیم تا بر روی یکدیگر اثر مستقیم نگذاشته و بتوان آنها را مدیریت کرد. این قابلیت به میزان قابل توجهی بر کیفیت کار موازی تأثیر میگذارد و کل روند توسعه را بهینه می کند. در ادامه در مورد چرخه و استاندارد شاخه بندی توضیح خواهم داد.
  • Tag: بخاطر سختی حفظ IP ها، نام های دامنه بوجود آمدند. به خاطر سختی به خاطر سپردن Hash های Commit ها نیز Tag ها بوجود آمدند. Tag ها به معنی برچسب هستند و شما میتوانید برای یک Commit برچسبی با اسم دلخواه (بعنوان مثال شماره نسخه) بگذارید تا در مواقع نیاز به راحتی به آن Commit دسترسی پیدا کنید.

چرخه استفاده از ابزار Git

بطور معمول اکثر پروژه ها با یک استارت اولیه شروع شده و بعد از گذراندن مراحلی به پایان میرسند ولی پروژه های نرم افزاری معمولا پایانی ندارند هرچند که از یک نقطه به بعد توسعه میتواند تنها رفع باگ باشد.

قبل از اینکه به مراحل برسیم بهتر است که سه قسمت اصلی ذخیره اطلاعات در Git را بررسی کنیم:

  • قسمت فایل های اصلی: در این قسمت فایل های مربوط به خود پروژه وجود دارند که توسعه دهنده آنها را می سازد یا ویرایش می کند.
  • قسمت index بندی: در این قسمت اسم و آدرس فایل های ایجاد شده یا تغییر داده شده توسط توسعه دهنده اضافه می شوند.
  • قسمت مخزن تغییرات: این قسمت مخزن بوده که اطلاعاتی مانند commit ها و شاخه ها و غیره نگهداری می شوند. وقتی توسعه دهنده Commit را ثبت می کند اطلاعات فایل هایی در قسمت index ثبت شده بودند توسط ابزار git با اطلاعات ثبت شده قبلی مقایسه شده و تمام تغییرات به همراه این Commit ثبت می شوند. از آنجایی که git یک DVCS می باشد همیشه یک مخزن تغییرات Local یا همان داخلی وجود دارد و می تواند یک یا چند مخزن Remote یا خارجی نیز وجود داشته باشد.

روند استفاده از Git بطور معمول و ساده ترین حالت به شرح زیر می باشد:

استفاده از Git - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

  • ساخت اولیه دایرکتوری پروژه و git init در آن یا گرفتن یک نسخه کپی از یک ریپازیتوری با git clone
  • ساخت و یا جا به جایی به شاخه یا همان Branch مورد نظر (در مورد نحوه شاخه بندی و یا همان Branching در ادامه صحبت خواهیم کرد)
  • ساخت و یا ویرایش فایل های مورد نظر برای انجام یک کار و بعد اضافه کردن آنها به Stage Area با استفاده از دستور git add
  • ثبت نهایی کار با Commit و نوشتن پیغام توضیح تغییرات که منجر به ذخیره تغییرات فایل ها در دایرکتوری .git می شود
  • در نهایت Push کردن Commit های صورت گرفته به Repository یا منبع خارجی یا اشتراکی در صورت وجود که باعث ثبت شدن تمام Commit ها در آن مخزن میشود.

دستورات پر کاربرد در Git

بعد از تمام این مباحث تئوری میرسیم به مباحث عملی و نحوه استفاده از Git:

کانفیگ و تنظیمات

کانفیگ و تنظیمات - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

ساخت یک مخزن، استارت پروژه

ساخت یک مخزن، استارت پروژه - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

کپی یک مخرن کامل از یک سرور

کپی یک مخرن کامل از یک سرور - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

اضافه کردن فایل ها به مرحله Stage

اضافه کردن فایل ها به مرحله Stage1 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

اضافه کردن فایل ها به مرحله Stage2 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

ثبت تغییرات یا همان Commit

ثبت تغییرات یا همان Commit - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

ثبت تغییرات یا همان Commit2 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

مشاهده تغییرات بین دو Branch یا بین فایل های فعلی و آخرین تغییرات ثبت شده

مشاهده تغییرات بین دو Branch - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

مشاهده تغییرات بین دو Branch1 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

بازگردانی به مراحل قبل

گیت1 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commitگیت2 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commitگیت3 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

مشاهده وضعیت Stage

مشاهده وضعیت Stage - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

حذف یک فایل و ثبت حذف شدن آن در Stage

حذف یک فایل و ثبت حذف شدن آن در Stage - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

مشاهده تمامی Commit ها و Commit هایی که شامل تغییرات یک فایل خاص میشوند

مشاهده تمامی Commit ها - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commitمشاهده تمامی Commitا - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

بر چسب یا همان Tag زدن بر یک Commit

بر چسب یا همان Tag زدن بر یک Commit - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

لیست کردن، ساختن و حذف Branch ها

1 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit2 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit3 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

جابجایی در Branch ها

1 1 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit2 1 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

ترکیب دو Branch

ترکیب دو Branch - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

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

ثبت ریموت سرور برای مخزن لوکال - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

ارسال تغییرات مخزن لوکال به ریموت

1 2 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit2 2 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit3 1 - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

گرفتن تغییرات از مخزن ریموت و ثبت در لوکال

گرفتن تغییرات از مخزن ریموت و ثبت در لوکال - آموزش Git از دستورات تا مدل شاخه بندی و پیام Commit

ساختاری برای پیام های Commit با عنوان Conventional Commit

اولین سوالی که امکان دارد برای شما پیش آید این است که چرا پیام های تغییرات باید دارای یک ساختار خاص باشند؟ جواب این سوال درست مانند جواب سوال “چرا از git استفاده کنیم ” است. راحتی نگهداری، مرور تغییرات و توسعه تیمی می تواند دلیل آن باشد.

در نظر بگیرید در یک تیم توسعه نقشی را بر عهده دارید (مانند DevOps یا برنامه نویس ارشد یا بخصوص Code Audit)  اگر هر برنامه نویس به سبک خود پیام Commit بنویسد و از شما خواسته شود از تغییرات CHANGELOG تهیه کنید یا عملکرد برنامه نویس را ارزیابی کنید و یا ایرادهای نگارشی یا باگ لاجیک پیدا کنید، شما چگونه اینکار را انجام خواهید داد بدون داشتن ریز تغییرات، قدم های کوچک و هدف های کوچک توسعه و بخصوص متن پیام تغییرات مناسب که با شفافیت تغییر و دلیل تغییر را برای شما تشریح کند؟

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

در آخر به این نتیجه میرسیم که داشتن یک ساختار یکسان برای پیام های Commit مانند داشتن زبان یکسان برای گفت و گو با دیگر اعضای گروه است. قطعا این مقوله بسیار کار گروهی را راحت تر می کند.

در ادامه به ساختار تعریف شده تحت عنوان Conventional Commit می پردازیم.

 مدل ساختار Conventional Commit

مدل ساختار Conventional Commit به شکل زیر است:

[optional scope] [optional body] [optional footer(s)]

اجزای مختلف:

  • type: به معنی نوع تغییر میباشد. مانند: fix, feat, build, chore, ci, docs, style, refactor و غیره. type به لیست ذکر شده محدود نمی باشد و در صورت وجود نوع بهتر میتوانید از آن استفاده کنید.
  • scope: این قسمت در پرانتز قرار می گیرد و برای مشخص کردن محدوده تأثیرگذاری می باشد. بعنوان مثال: api, lang, core, util و غیره باشد.
  • description: توضیح مختصر خطی درباره تغییر اعمال شده. بعنوان مثال: ci: add python3.8 env test
  • body: در صورت نیاز به توضیحات بیشتر می توانید علاوه بر توضیح خطی ای که در خط اول قرار داده اید, در این قسمت توضیحی تا یک پاراگراف نیز قرار دهید.
  • footer: نکته ها را در این قسمت میتوانید قرار دهید. مانند ارجاء به یک issue یا یک لینک نمایانگر یک کلمه در توضیحات و یا غیره…

نکته: قسمت های scope و body واگر توجه کرده باشید, سورس اکثر کتابخانه ها و یا برنامه های کاربردی ای که به یک زبان نوشته شده اند دارای ساختار دایرکتوری و فایل هایی با نام footer اختیاری می باشند.

نکته: در جمله قسمت description از فعل حال استفاده کنید بجای فعل گذشته مانند: add بجای added.

در صورت وجود تغییر در api ارائه شده به کاربر یا هر تغییری که دارای backward compatibility صد در صد نمی باشد باید در قسمت footer متن BREAKING CHANGE: به همراه تشریح ناسازگاری رو به روی آن را بنویسید.

در صورت نبود نیاز به تشریح میتوانید از ! بعد از type یا scope نیز به جای توضیحات در footer استفاده کنید.

مثال برای تمامی حالت ها:

feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files

refactor!: drop support for Node 6

refactor!: drop support for Node 6
BREAKING CHANGE: refactor to use JavaScript features not available in Node 6

ساختاری مناسب برای شاخه بندی

successful-git-model
successful-git-model

شاید برای شما سوال پیش آمده باشد که این شاخه بندی که سیستم git در اختیار ما قرار میدهد را باید چگونه استفاده کنیم.

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

این مدل یک ساختار generic برای branch بندی رشته تغییرات کد میباشد که بر روی اکثر codebase ها قابل پیاده سازی است و قوانین ساده ای دارد.

مزایای این ساختار Branch بندی

  • جلوگیری از merge conflict تا حد ممکن
  • تقسیم وظایف راحتتر
  • راحتی کنسل کردن توسعه یک feature بدون هیچگونه تأثیر در دیگر شاخه های توسعه
  • فراهم سازی توسعه موازی حتی برای scale بالا

شاخه های مختلف این ساختار Branch بندی

این ساختار از دو شاخه اصلی بهره میبرد:

  • master: در این شاخه تنها release های نهایی قرار میگیرند. تغییرات در این شاخه تنها و تنها از طریق merge شدن شاخه های دیگر رخ خواهد داد.
  • dev: در این شاخه توسعه اصلی و طبق اهداف اصلی پروژه صورت خواهند گرفت. تمامی تغییرات در دیگر شاخه ها در نهایت با این شاخه merge خواهند شد.
  • feature branches: شاخه هایی هستند میتوانند اسامی خاص هدف خود را داشته باشند و این اهداف باید خارج از هدف پایه کد منبع باشند. این شاخه از شاخه dev نشئت میگیرند و پس از رسیدن به هدف با شاخه dev ادغام یا همان merge خواهند شد. توسعه این شاخه ها با رسیدن به هدف و merge شدن با شاخه dev اتمام یافته و در صورت نیاز به توسعه بیشتر آن feature شاخه جدیدی باز خواهد شد. نگهداری این شاخه ها پس از اتمام کار غیر ضروری است.
  • release branches: شاخه های تکمیل و بسته بندی برای release هستند که تنها از از شاخه dev نشئت میگیرند و در آخر به شاخه master و dev ادغام می شوند. در این شاخه عملیات هایی مانند تغییر نسخه در کامنت ها, ساخت ChangeLog و غیره صورت میگیرد. نکته: تغییر فایل های کانفیگ مربوط به پکیج بندی در شاخه dev قرار انجام میشود و نه شاخه ها release.
  • hotfix branches: این شاخه تنها برای رفع باگ های حیاتی ساخته میشود, از master نشئت میگیرد و در نهایت با dev و master ادغام میشود. یکی از بزرگترین عاملان merge conflict نیز معمولا این شاخه ها هستند.

نکته: نام گذاری شاخه ها کاملا اختیاری است و در این آموزش تنها برای ساده سازی نام گذاری شده اند.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *


دکمه بازگشت به بالا