پرش به مطلب اصلی

گردش کار گیت یا Git Flow

در این نوشته به لزوم تعریف و رعایت یک گردش کار (workflow) برای انجام وظایف خود می‌پردازیم و در نهایت یک گردش کار برای انجام وظایف خود با استفاده از ابزار گیت معرفی می‌کنیم.

چرا از یک گردش کار استفاده کنیم؟

به عنوان یک توسعه‌دهنده کارهای مختلفی به ما واگذار می‌شود. اگر بدون استفاده از فرآیند مشخص برای انجام هر کار، مشغول آن شویم و امکان تفکیک کارهای مختلف از یکدیگر را نداشته باشیم به سرعت به شرایط پیچیده‌ای دچار خواهیم شد که ادامه کار را برای ما سخت خواهد کرد.

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

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

داستان ۳: به منظور انجام آزمون دستی قبل از انتشار تغییرات برای کاربران اصلی، یک نسخه از تغییرات را در محیط آزمایشی منتشر می‌کنید و پس از تایید، آن تغییرات را برای کاربر منتشر می‌کنید. در این حین در شرایطی مانند داستان ۱ و داستان ۲ قرار می‌گیرید. با این تفاوت که به دلیل وجود تنها یک محیط آزمون مجبور هستید تا همه تغییرات را در یک محل قرار دهید. در این شرایط ممکن است برخی از تغییرات موجود در این محل امکان انتشار برای کاربر را نداشته باشند و بخواهید برخی دیگر را منتشر کنید.

داستان ۴: تغییرات جزئی وجود دارند که می‌خواهید تنها در برخی محیط‌ها لحاظ شوند. برای مثال میخواهید در محیط آزمون بار به جای ارسال رمز یکبار مصرف از طریق پیامک، رمز در پاسخ درخواست برای کاربر ارسال شود. همچنین ممکن است این تفاوت‌ها برای کد منبع نباشند و تنظیمات محیطی سیستم CI/CD که بر اساس هر شاخه تنظیم می‌شوند نیاز به تنظیم مقادیر متفاوت داشته باشد.

نمونه‌های دیگری نیز وجود دارد که می‌تواند شرایط پیچیده‌ای ایجاد کند و پیشبرد کار را برای شما سخت کند.

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

از چه گردش کاری استفاده کنیم؟

گیت یک ابزار منعطف است و فرآیند استانداردی برای استفاده از آن وجود ندارد. با این حال برای ایجاد یک مسیر توسعه هموار و جلوگیری از بروز شرایط پیچیده راهکارهای مختلفی توسط افراد و سازمان‌های مختلف ارائه شده است. از جمله این راهکارها می‌توان به موارد زیر اشاره کرد:

۱. گردش کار متمرکز

در این روش همه تغییرات روی شاخه اصلی (برای مثال main) قرار میگیرد. قبل از اعمال تغییرات انجام شده روی این شاخه ابتدا تغییرات جدید این شاخه دریافت(pull) شده و بعد از رفع تناقضات در نسخه محلی روی شاخه اصلی ارسال (push) می‌شود.

۲. گردش کار Feature Branching

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

۳. گردش کار git-flow

این روش مشابه روش Feature Branching است با این تفاوت که در آن علاوه بر شاخه اصلی شاخه‌های دائمی دیگری با نقش مشخص تعریف می‌شوند.

۴. گردش کار GitLab Flow

با گسترش DevOps و فرهنگ Agile نیاز به یک روش بهینه‌تر برای انتشار تغییرات ایجاد شد. به همین دلیل شرکت‌هایی نظیر GitHub و GitLab روش پیشنهادی خود را به شکل عمومی مطرح کردند. این نسخه ساده‌تری از git-flow را ارائه می‌کند. در این روش تمامی تغییرات به شاخه main برده می‌شوند با این تفاوت که به جای ایجاد شاخه develop برای توسعه و ساخت feature branch ها، مستقیما از خود شاخه main استفاده می‌شود.

همچنین از یک شاخه به نام production استفاده می‌شود تا تغییرات را برای کاربر نهایی منتشر کند. در این روش تیم توسعه می‌تواند تعدادی شاخه پیش از انتشار عمومی را بین main و production ایجاد نماید. برای مثال تغییرات از شاخه main به شاخه staging بروند و پس از بررسی به شاخه production منتقل شوند.

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

گردش کار پیشنهادی ما

گردش کار پیشنهادی ما شباهت زیادی به گردش کار گیتلب دارد. در این گردش کار مشابه گیتلب تغییرات روی feature branch هایی که از شاخه main ساخته شده‌اند انجام می‌شوند و می‌توان از شاخه production برای استقرار در محیط پروداکشن استفاده کرد.

مسئله ای که در روش‌های قبل پوشش داده نمی‌شوند محیط‌های مختلف اجرا است. در روش GitLab Flow تنها یک شاخه نهایی برای استقرار اپلیکیشن (شاخه production) در نظر گرفته می‌شود در حالی که ممکن است نرم‌افزار در محیط‌های مختلف و با مخاطبین مختلف مستقر شوند و هر محیط ویژگی‌های مربوط به خود را داشته باشد(مشابه داستان ۴). از طرفی این ویژگی‌ها ممکن است بسیار جزئی باشند و ایجاد یک انشعاب (fork) از کل مخزن منطقی نباشد.

در روش برای هر محیط که در آن استقرار انجام می‌شود یک شاخه در نظر گرفته می‌شود. این محیط‌ها به دو دسته محیط‌های پایدار و محیط‌های ناپایدار تقسیم می‌شوند.

محیط پایدار محیطی است که تغییرات موجود روی آن تنها شامل تغییرات آزموده شده‌ای است که برای کاربران نهایی سامانه قابل انتشار است.

محیط ناپایدار محیطی است که ممکن است شامل تغییراتی باشد که پایدار نیستند و ممکن است هیچ‌گاه برای کاربر نهایی منتشر نشوند. ویژگی دیگر این محیط‌ها این است که حتی با حذف کامل آن‌ها مشکلی برای ادامه توسعه و کاربران نهایی ایجاد نمی‌شود و به سادگی امکان ساخت مجدد دارند.

برای مثال شاخه production که برای محیط پایدار پروداکشن که کاربران اصلی از آن استفاده می‌کنند ایجاد می‌شود. همچنین شاخه beta که برای محیط ناپایدار آزمایشی که تنها کاربران آزمونگر از آن استفاده می‌کند ایجاد می‌شود.

تفاوت بین محیط‌های پایدار و محیط‌های ناپایدار در این است که feature branch‌ها به شکل مستقیم امکان قرار گرفتن روی شاخه‌های مربوط به محیط‌های ناپایدار را دارند اما شاخه یک محیط پایدار تنها تغییرات موجود در main را دریافت می‌کند.

تنها استثنا برای تغییراتی است که باید فقط روی یک محیط خاص در دسترس باشند. feature branch مربوط به این تغییرات بعد از آزموده شدن روی شاخه‌های ناپایدار می‌توانند مستقیما روی شاخه پایدار مربوط قرار گیرند. برای این شاخه‌ها باید مستنداتی وجود داشته باشد که تغییرات مخصوص به آن‌ها را توضیح دهد.

مثال‌هایی از به کارگیری گردش کار پیشنهاد شده

مثال ۱: شرایط داستان ۳

با حضور: شما(توسعه دهنده)، طراح رابط کاربری، مدیر محصول

فرض کنید روی یک سایت لیست کارها (todo list) کار می‌کنیم و مشغول پیاده سازی قابلیت ستاره‌دار کردن کارها هستیم.

رویداد صفرم: برای پیاده سازی این قابلیت یک شاخه از شاخه اصلی یعنی main به نام starred-task ایجاد کرده ایم و تغییرات را روی آن انجام می‌دهیم.

رویداد اول: طراح رابط کاربری می‌خواهد پیاده‌سازی انجام شده را بررسی کند تا مطمئن شود ستاره‌ها به اندازه کافی گرد هستند! بنابراین شما یک Merge Request در گیتلب از شاخه starred-task به شاخه beta ایجاد می کنید و آن را merge می کنید تا استقرار روی محیط آزمایشی انجام شود و طراح بتواند پیاده‌سازی را بازبینی کند.

رویداد دوم: مدیر محصول از شما می‌خواهد که رنگ مربوط به کارهای انجام شده را کمرنگ‌تر کنید و به شما می‌گوید که اولویت این کار از قابلیت ستاره‌دار کردن کارها بیشتر است. در این حالت شما شاخه main را checkout می‌کنید و یک شاخه جدید از روی آن با نام task-opacity ایجاد می‌کنید و کار را روی آن انجام می‌دهید.

رویداد سوم: کار شما تمام شده است و برای این که مدیر محصول مطمئن شود که کارهای انجام شده به اندازه کافی کمرنگ شده‌اند مشابه روند قبل یک Merge Request ایجاد می‌کنید تا تغییرات روی محیط آزمایشی مستقر شوند. اما GitLab به شما خطا می‌دهد که یک conflict بین تغییرات وجود دارد.

رویداد چهارم: متاسفانه حق با گیتلب است و شما در همان خطی که آیکون ستاره را اضافه کردید تغییرات مربوط به کمرنگ کردن کار را انجام داده اید. برای رفع این conflict مجبور هستید تا merge را به صورت محلی انجام دهید. برای این کار شاخه beta را checkout می‌کنید و دستور git merge origin/task-opacity را اجرا می‌کنید و سپس با git push تغییرات را به گیتلب ارسال می‌کنید و تغییرات شما روی محیط آزمایشی مستقر شوند.

نکته: این مسئله در زمان merge کردن شاخه starred-tasks با شاخه main نیز مجدد تکرار خواهد شد. بنابراین یک Merge Request به صورت Draft از شاخه starred-tasks به شاخه main ایجاد می‌کنید و توضیحاتی در مورد conflict موجود با تغییرات این برنچ را در آن یادداشت می‌کنید.

رویداد پنجم: درنهایت بعد از تایید مدیر محصول یک Merge Request از شاخه task-opacity به شاخه main ایجاد می‌کنید و آن را merge می کنید. این کار به شما کمک می‌کند تا اگر نیاز به توسعه جدیدی باشد تغییرات جدید را در feature branch مربوط به آن داشته باشید.

رویداد ششم: در نهایت یک Merge Request از شاخه main به شاخه production ایجاد می‌کنید تا تغییرات را در محیط پروداکشن قرار دهید. اما امروز پنج شنبه است و قواعد سازمان اجازه انتشار در روز آخر هفته را نمی‌دهد و این باعث می‌شود که انتشار روی محیط پروداکشن را انجام ندهید.

رویداد هفتم: تا شنبه وقت زیادی است. به شاخه starred-tasks باز می‌گردید و به وظیفه قبلی خود میپردازید.

رویداد هشتم: روز شنبه نیز به عنوان اولین کار Merge Request مربوط به محیط پروداکشن را با اطلاع مدیر محصول merge می‌کنید.

مطالعه بیشتر و منابع