یک مدل موفق برای Git flow : Git baranching

توی این پست میخوام Git flow (گیت فلو) را بهتون معرفی کنم.منبع اصلی این مقاله سال ۲۰۱۰ منتشر شد و یک مدل پیشنهادی-قراردادی برای استفاده تیمی از ابزار قدرتمند Git هست و در حال حاضر مدلی هستش که کم‌و‌بیش به عنوان مدل کاری تیم‌ها روی گیت جا افتاده و بسیاری از تیم‌های بزرگ از این مدل یا مدل شخصی‌سازی شده برگرفته از Git flow استفاده میکنن.

در ابتدا باید به این نکته اشاره کنم که برای مطالعه ادامه این پست باید آشنایی اولیه با مفاهیم گیت (مثل Branch ,commit ,fetch ,pull, ...) و دستوراتش داشته باشید.با یه سرچ ساده توی گوگل با محتوای فراوانی در رابطه با شروع به کار با Git پیدا خواهید کرد و اگرقصد یادآوری دارید، این لینک (از وبلاگ میکائیل اندیشه)که لیستی از دستورات Git هست را بهتون پیشنهاد میدم.اگر هم قبلا با گیت آشنایی دارید بهتره وقت را تلف نکنیم و بریم که با یه مدل ساده، روان و در عین حال بسیار کاربردی هنگام کار تیمی روی سورس کد آشنا بشیم.

نمودار کلی از جریان کاری git-flow
نمودار کلی از جریان کاری git-flow

توی تصویر بالا پیکان‌های عمود نشان‌دهنده کامیت(commit) و پیکان‌های مایل به طرفین نشان‌دهنده ادغام (merge) هستند.

شاخه‌های اصلی | Main branches

در هسته این مدل بسیاری از مفاهیم از مثال‌های کاربردی دنیای واقعی گرفته شده است.مخزن اصلی(که معمولا آنلاین هست)، دارای دو شاخه(branch) اصلی میباشد.

  • master
  • develop

شاخه master که برای هر کاربر گیت کلمه آشنایی است و به طور موازی شاخه develop قرار گرفته است.

ما شاخه origin/master را هنگامی که به نسخه آماده انتشار نیاز داشتیم به عنوان شاخه اصلی در نظر خواهیم گرفت زیرا که Head pointer آن همواره به یک نسخه آماده بهره‌برداری(production) اشاره خواهد کرد.

همچنین Head pointer شاخه origin/develop همواره به یک نسخه با آخرین تغییرات و ویژگی‌های قابل انتشار(release) اشاره خواهد کرد.

طول عمر شاخه‌های اصلی نامحدود هست یعنی تا وقتی ما در حال توسعه این محصول هستیم با این دو تا شاخه سروکار داریم.

هنگامی که سورس کد داخل شاخه توسعه به یک حالت پایدار برسد و آماده‌ی انتشار باشد، همه‌ی تغییرات باید در شاخه master ادغام (merge) شود و به عنوان یک نسخه تگ‌گذاری شود.در ادامه به طور کامل چگونگی این فرایند را توضیح خواهم داد.

بنابراین هر دفعه که تغییرات در شاخه master ادغام میشود یک نسخه قابل بهره‌برداری آماده شده است.توی این مرحله شما میتونید با استفاده از Git hook script یا CD/CI به صورت اتوماتیک، با هر commit در شاخه اصلی (master)، فرایند انتشار نسخه جدید برنامه را روی سرور انجام دهید.(البته اگه قراره برنامه شما در نهایت روی سرور قرار بگیره)

شاخه‌های حامی | Supporting branches

در کنار شاخه‌های اصلی master و develop مدل توسعه ما از چند شاخه حامی برای

  • کدنویسی موازی بین اعضای تیم
  • راحت شدن رهگیری ویژگی‌های برنامه و حفظ تاریخچه‌ تغییرات
  • آماده‌سازی برای انتشار نسخه بعدی
  • و تسریع بر‌طرف کردن باگ‌های محصول در حال استفاده

بهره میبره.

طبق لیست زیر سه تا شاخه حامی داریم:

  • Feature branches
  • Release branches
  • Hotfix branches

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

شاخه ویژگی(Feature branches)

نمای کاری شاخه feature
نمای کاری شاخه feature

تنها میتواند از شاخه develop منشعب شود.

تنها میتواند در شاخه develop ادغام شود.

قاعده نامگذاری : هر اسمی به جز (master-*, develop, release-*, or hotfix)

این شاخه برای توسعه یک ویژگی جدید استفاده میشود.در هنگام ایجاد شاخه ممکن است نسخه هدفی که این ویژگی ممکن است در آن قرار بگیرد مشخص نشده باشد.شاخه ویژگی تا زمانی وجود خواهد داشت که در آن ویژگی در حال توسعه باشد.در نهایت این شاخه در شاخه develop ادغام خواهد شد تا نهایتا در نسخه بعدی منشتر شود.

دقت کنید هر ویژگی باید دارای یک شاخه مجزا با نام مشخص (به سور مثال AuthFeature) باشد و چند برنامه‌نویس میتوانند به صور همزمان روی یک ویژگی کار کنند.

معمولا شاخه ویژگی در مخزن توسعه‌دهنده وجود خواهد داشت (البته اگه فقط یک نفر روی این ویژگی کار کند) و در مخزن origin قرار نمیگیرد.

ایجاد شاخه ویژگی

هنگام شروع کار روی یک ویژگی جدید از شاخه develop منشعب میشود.

$ git checkout -b myfeature develop
//Switched to a new branch "myfeature"

ادغام شاخه یک ویژگی در شاخه develop

ویژگی‌های کامل شده در شاخه develop ادغام میشوند تا در نسخه بعدی قرار داده شود.

$ git checkout develop
//Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
//(Summary of changes)
$ git branch -d myfeature
//Deleted branch myfeature (was 05e9557).
$ git push origin develop

پرچم no-ff-- باعث میشود که همیشه ادغام یک commit جدید ایجاد کند، حتی اگر ادغام بتواند با یک ارسال سریع(fast forward) انجام شود.این کار باعث میشود تاریخچه شاخه feature از بین نرود.

مقایسه دو حالت خام یا با پرچم
مقایسه دو حالت خام یا با پرچم


توی تصویر سمت راست خیلی سخته که بتونید تاریخچه commit هایی که یک feature را ساخته‌اند را ببینید.

شاخه انتشار(Release branches)

تنها میتواند از شاخه develop منشعب شود.

تنها میتواند در شاخه‌های develop و master ادغام شود.

قاعده نامگذاری : *-release

شاخه release برای آماده‌سازی انتشار بعدی (حل باگ‌های کوچک، نهایی سازی تغییرات و تست‌های قبل از انتشار) برنامه مورد استفاده قرار می‌گیرد.یکی از مزایای ایجاد شاخه release این است که شاخه develop برای دریافت ویژگی‌های جدید(ویژگی‌هایی که برای انتشار بعدی در نظر گرفته شده‌اند) آماده میشود.

زمان درست انشعاب شاخه release از develop هنگامی است که develop یک شرایط پایدار و هدف‌گذاری شده برای انتشار را دارا باشد و تمام ویژگی‌های مورد انتظار برای انتشار در شاخه develop ادغام شده باشد.

ایجاد شاخه انتشار

شاخه‌های ‌‌release از شاخه develop منشعب میشود.برای فرضی، ورژن فعلی برنامه ۱.۱.۵ است و ما قصد انتشار نسخه بعدی برنامه را داریم.وضعیت شاخه develop آماده برای انتشار بعدی است و ما تصمیم گرفته‌ایم این نسخه ۱.۲ (به جای ۱.۱.۶ یا ۲.۰) شماره‌گذاری شود.بنابراین ما یک شاخه انتشار منشعب میکنیم و آن را به شکلی نامگذرای میکنیم که نشان‌دهنده شماره نسخه بعدی باشد.

$ git checkout -b release-1.2 develop
//Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
//Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
//[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)

پس از ایجاد شاخه انتشار و عزیمت به آن، ما شماره نسخه (version number) را داخل پروژه عوض میکنیم. bump-version.sh یک شل اسکریپت (shell script) است که نسخه مورد نظر ما را داخل فایل‌های پروژه منعکس میکند(صد البته با تغییر چند فایل).سپس کامیت به همراه پیام شماره نسخه جدید انجام میشود.

این شاخه جدید تا زمانی که تست میشود و باگ‌های آن در حال برطرف شدن هستند، وجود خواهد داشت و بعد از آن در شاخه‌های master و develop ادغام خواهد شد.افزودن ویژگی‌های جدید به این شاخه ممنوع میباشد و ویژگی‌های جدید باید در شاخه develop ادغام شوند و بنابراین باید تا انتشار نسخه بعدی منتظر بمانند.

خاتمه شاخه انتشار(Release branches)

هنگامی که وضعیت شاخه انتشار برای یک انتشار واقعی برای بهره‌برداری آماده شد، باید عملیاتی به ترتیب زیر انجام شود.

  1. شاخه release در شاخه master ادغام شود(هر کامیت در شاخه master یک نسخه آماده بهره‌برداری است).
  2. در قدم بعدی باید برای ارجاع راحت‌تر در آینده این کامیت باید تگ‌گذاری شود.
  3. و در نهایت تغییرات ایجاد شده روی شاخه release باید در شاخه develop ادغام شود تا نسخه بعدی انتشار شامل حل باگ‌های(bug fixes) این انتشار باشد.

دو قدم اول در git

$ git checkout master
//Switched to branch 'master'
$ git merge --no-ff release-1.2
//Merge made by recursive.
//(Summary of changes)
$ git tag -a 1.2

حالا انتشار نسخه جدید انجام شده است و برای ارجاع راحت‌تر در آینده تگ‌گذاری شده است.

برای حفظ تغییرات اعمال شده در شاخه release، ما نیاز داریم آن‌ها را در شاخه develop ادغام کنیم.

$ git checkout develop
//Switched to branch 'develop'
$ git merge --no-ff release-1.2
//Merge made by recursive.
//(Summary of changes)

در این مرحله ممکن است به تداخل ادغام (merge conflict) بر بخورید که البته مشکلی نیست، آن را برطرف کنید و دوباره کامیت کنید.

حالا که کار ما با شاخه release تمام شده است، میتوانیم آن را حذف کنیم.

$ git branch -d release-1.2
//Deleted branch release-1.2 (was ff452fe)

شاخه رفع اشکال سریع(Hotfix branches)

تنها میتواند از شاخه master منشعب شود.

تنها میتواند در شاخه‌های develop و master ادغام شود.

قاعده نامگذاری : *-hotfix

شاخه hotfix از این لحاظ که فقط برای رفع باگ‌ و انتشار نسخه جدید به کا میرود بسیار شبیه شاخه release است ولی با این تفاوت که خاستگاه آن‌ ضرورت رفع باگ‌های ناگهانی روی محصول در حال استفاده است.

هنگامی که در محصول در حال استفاده یک باگ پیدا شود و نیاز است تا بلافاصله برای رفع آن اقدام شود، شاخه hotfix باید از آخرین tag شاخه master منشعب شود.

ذات این شاخه اجازه میدهد در حالی که یک نفر در حال رسیدگی و برطرف کردن باگ‌های محصول در حال استفاده است، بقیه اعضای تیم روی کار خودشون تمرکز کننند.

ایجاد شاخه Hotfix

شاخه hotfix از شاخه master منشعب میشود.به طور فرضی نسخه ۱.۲، نسخه در حال استفاده کنونی است و یک باگ شدید روی آن دردسر ساز شده است.در همین حین نسخه در حال توسعه روی شاخه develop غیر پایدار و در نتیجه غیر‌قابل انتشار است.در این شرایط شما یک شاخه hotfix ایجاد و به رفع باگ میپردازید.

$ git checkout -b hotfix-1.2.1 master
//Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
//Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
//[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

فراموش نکنید که شماره نسخه جدید(در اینجا ۱.۲.۱) را اعمال کنید.

سپس باگ را رفع کنید و در یک یا چند کامیت آن را به پایان ببرید.

خاتمه شاخه Hotfix

هنگامی که باگ برطرف شد، باگ‌های رفع شده باید در شاخه master و در عین حال شاخه develop ادغام شود(به منظور اعمال رفع باگ در نسخه‌های بعدی).تا اینجا کاملا شبیه پایان دادن به شاخه انتشار بود.

در قدم اول شاخه master را بروزرسانی میکنیم و نسخه را تگ‌گذاری میکنیم.

$ git checkout master
//Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
//Merge made by recursive.
//(Summary of changes)
$ git tag -a 1.2.1

سپس باگ‌های رفع شده را در شاخه develop ادغام میکنیم.

$ git checkout develop
//Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
//Merge made by recursive.
(Summary of changes)

یک حالت خاص توی این مرحله وجود دارد که، اگر در حال حاضر شاخه release وجود داشت، به جای ادغام hotfix در شاخه develop آن را در شاخه release ادغام خواهیم کرد.در این صورت بعد از ادغام release در develop در نهایت تغییرات hotfix در develop نیز ادغام خواهد شد.

در نهایت شاخه hotfix را حذف میکنیم.

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).

اگر انتقاد و یا پیشنهادی در مورد این مقاله یا مدل git-flow (یا هر مدلی دیگه‌ای که شما از git استفاده میکنید) دارید خوشحال میشم همین زیر برام کامنت کنید.