چهارشنبه, 21 مرداد 1405

Git Flow

...

” وقتی یک پروژه بزرگ‌تر میشه و چند نفر همزمان روی اون کار می‌کنن، دیگه مدیریت روند توسعه به سادگی یک پروژه شخصی نیست. Git Flow کمک می‌کنه برای توسعه featureها، آماده‌سازی نسخه‌های جدید و رفع مشکلات production مسیر مشخصی داشته باشیم. “

وقتی روی یک پروژه شخصی کار می‌کنی، احتمالاً مدیریت Git خیلی پیچیده نیست.

یک Branch داری، تغییراتت رو انجام میدی، commit می‌زنی و در نهایت تغییرات رو push می‌کنی.

همه چیز ساده هست.

اما...

فرض کن پروژه بزرگ‌تر شده و چند نفر همزمان روی اون کار می‌کنن.

یکی داره روی صفحه ورود کار می‌کنه.

یکی دیگه مشغول ساخت داشبورد هست و خودت هم داری یک قابلیت جدید به پروژه اضافه می‌کنی.

اگه همه مستقیماً روی main کار کنن، خیلی زود با مشکلات مختلفی روبه‌رو میشید.

ممکنه یک feature هنوز کامل نشده باشه، اما وارد نسخه اصلی پروژه بشه.

یا یک تغییر جدید باعث خراب شدن بخشی از پروژه بشه.

یا چند نفر همزمان روی یک بخش کار کنن و Merge کردن تغییراتشون تبدیل به یک دردسر بزرگ بشه.

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

اینجاست که یک سؤال مهم به وجود میاد:

چطور باید Branchهای پروژه رو مدیریت کنیم تا توسعه، انتشار و رفع مشکلات production مسیر مشخصی داشته باشن؟

یکی از روش‌هایی که برای حل این مشکل به وجود اومده، Git Flow هست.


Git Flow چیست؟

Git Flow یک روش برای مدیریت Branchها در Git هست.

به جای اینکه همه تغییرات رو مستقیماً روی یک Branch انجام بدیم، برای هر نوع کاری Branch مخصوص خودش رو داریم.

مثلاً:

  • یک Branch برای نسخه اصلی و production

  • یک Branch برای توسعه

  • Branchهای جداگانه برای featureها

  • Branchهایی برای آماده‌سازی نسخه جدید

  • و Branchهایی برای رفع مشکلات فوری production

در واقع Git Flow به ما میگه:

هر نوع تغییر، باید مسیر مشخص خودش رو در پروژه داشته باشه.

در ادامه، قدم‌به‌قدم با هرکدوم از این Branchها آشنا می‌شیم و می‌بینیم هرکدوم چه کاربردی دارن و چه زمانی ازشون استفاده می‌کنیم.

برای اینکه بهتر متوجه بشیم، اول با یه مثال ببینیم اصلاً چرا به چنین ساختاری نیاز داریم.


مشکل کار کردن مستقیم روی main

فرض کن پروژه‌ای داریم که نسخه فعلی اون روی main قرار داره.

امروز تصمیم می‌گیریم یک سیستم احراز هویت جدید به پروژه اضافه کنیم.

قبل از اینکه شروع کنیم به کار روی پروژه، معمولاً اولین کاری که انجام میدیم اینه که مطمئن بشیم همه چیز به‌روز هست و آخرین تغییرات تیم رو داریم.

برای همین میایم آخرین وضعیت پروژه رو از مخزن می‌گیریم:

git checkout main
git pull

این دستورات یعنی چی؟

  • git checkout main → رفتن روی Branch به اسم main

  • git pull → گرفتن آخرین تغییرات از Remote Repository

در نسخه‌های جدید Git می‌تونیم برای جابه‌جایی بین Branchها از git switch هم استفاده کنیم:

git switch main
git pull

در این مقاله برای ساده موندن مثال‌ها بیشتر از git checkout استفاده می‌کنیم، چون هنوز هم در بسیاری از پروژه‌ها و آموزش‌های Git دیده میشه.

بعد از اینکه مطمئن شدیم پروژه به‌روز هست، کار روی feature جدید رو شروع می‌کنیم.


حالا فرض کن چند ساعت روی یک قابلیت جدید کار کردیم.

مثلاً صفحه ورود رو جلو بردیم، اما هنوز بخش‌هایی مثل ثبت نام و بازیابی رمز عبور کامل نشده.

در این حالت اگه بخوایم تغییرات رو commit و push کنیم، در واقع داریم یک feature نیمه‌کاره رو وارد main می‌کنیم.

ممکنه پروژه همچنان اجرا بشه، اما این تغییرات می‌تونن نسخه اصلی پروژه رو ناپایدار کنن.

حالا فرض کن یک نفر دیگه همزمان روی پروژه کار می‌کنه و تغییرات خودش رو وارد main می‌کنه.

کم‌کم مدیریت پروژه سخت میشه.

البته این به معنی بد بودن کار با main نیست.

در بعضی Workflowها (روش کار و مدیریت پروژه)، مثل GitHub Flow،

main دقیقاً Branch اصلی توسعه هست و تغییرات از طریق Branchهای موقتی و Pull Request وارد اون میشن.

مسئله اینجاست که اگه تیم بخواد بین توسعه، نسخه در حال آماده‌سازی و production مرز مشخصی داشته باشه، یک ساختار ساده مثل main و Feature Branch ممکنه کافی نباشه.

اینجاست که develop وارد داستان میشه.


دو Branch اصلی

در Git Flow کلاسیک، دو Branch اصلی داریم:

main
develop

هر کدوم هم وظیفه متفاوتی دارن.

main

main نماینده نسخه اصلی و قابل انتشار پروژه است.

به زبان ساده:

چیزی که داخل main قرار داره، باید نماینده یک نسخه قابل انتشار از پروژه باشه.

قرار نیست هر feature ناقصی مستقیماً وارد این Branch بشه.


develop

develop جاییه که تغییرات جدید پروژه در اون جمع میشن.

featureهای مختلف در Branchهای جداگانه توسعه پیدا می‌کنن و وقتی آماده شدن، وارد develop میشن.

پس اگه خیلی ساده بخوایم بگیم:

                    ┌── feature/login
                    │
main ───────────── develop ─── feature/dashboard
                    │
                    └── feature/profile

در این ساختار، main نماینده نسخه منتشرشده هست و develop محل جمع شدن تغییرات نسخه بعدی پروژه هستش.


Feature Branch چیست؟

Feature Branch برای توسعه یک قابلیت یا بخش جدید از پروژه استفاده میشه، بدون اینکه تغییرات اون مستقیماً وارد Branch اصلی توسعه بشن.

حالا فرض کن می‌خوایم قابلیت ورود رو به پروژه اضافه کنیم.

به جای اینکه مستقیم روی develop کار کنیم، یک Branch جدید می‌سازیم:

git checkout develop
git checkout -b feature/login

اینجا چه اتفاقی افتاد؟

  • git checkout develop → رفتن روی Branch توسعه

  • git checkout -b feature/login → ساختن یک Branch جدید به اسم feature/login و رفتن روی اون

پس این دستور:

git checkout -b feature/login

تقریباً یعنی:

«از Branch فعلی یک شاخه جدید بساز و برو داخلش.»

در نسخه‌های جدید Git می‌تونیم همین کار رو با switch انجام بدیم:

git switch develop
git switch -c feature/login

حالا تغییرات مربوط به قابلیت ورود داخل همین Branch انجام میشن.

مثلاً:

develop
   │
   └── feature/login

در طول توسعه می‌تونیم چندین commit داشته باشیم:

git add .

git commit -m "add login form"

git commit -m "add authentication logic"

git commit -m "handle login validation"

تا زمانی که feature کامل نشده، کاری با develop نداریم.

این موضوع یک مزیت مهم داره.

اگه وسط کار متوجه بشیم قابلیت ورود هنوز آماده نیست، تغییرات ما همچنان از develop جدا هستن و روی Branch اصلی توسعه تأثیری ندارن.


وقتی Feature آماده شد

فرض کن ورود کامل شده.

حالا وقتشه تغییرات رو وارد develop کنیم.

اینجا معمولاً دو روش داریم.

روش ۱: Merge مستقیم

اگر تیم تصمیم گرفته باشه Merge رو مستقیم انجام بده، می‌تونیم بنویسیم:

git checkout develop
git merge feature/login

یعنی:

  • اول میریم روی develop

  • بعد تغییرات feature/login رو وارد develop می‌کنیم

بعد از Merge کردن، Feature Branch دیگه لزوماً مورد نیاز نیست و می‌تونیم اون رو حذف کنیم:

git branch -d feature/login

البته این کار به Workflow تیم بستگی داره.


روش ۲: Pull Request

در بسیاری از پروژه‌های تیمی، به جای Merge مستقیم، تغییرات از طریق Pull Request بررسی میشن.

Pull Request یعنی:

«من تغییراتم رو آماده کردم، لطفاً اون‌ها رو بررسی کن و اگه مورد تأیید بود، وارد Branch مقصد کن.»

مثلاً:

feature/login
       │
       │ Pull Request
       ▼
    develop

Pull Request خودش یک دستور Git نیست.

معمولاً روی سرویس‌هایی مثل GitHub یا GitLab ساخته میشه و اعضای تیم می‌تونن:

  • کد رو بررسی کنن

  • درباره تغییرات نظر بدن

  • تست‌ها رو اجرا کنن

  • مشکلات احتمالی رو پیدا کنن

  • و در نهایت تغییرات رو Merge کنن

پس Pull Request بیشتر بخشی از فرآیند همکاری تیمی و Code Review هست.


چند Feature همزمان

حالا فرض کن همزمان سه نفر روی پروژه کار می‌کنن.

یکی ورود رو توسعه میده.

یکی داشبورد.

و نفر سوم سیستم Notification رو.

ساختار Branchها می‌تونه چیزی شبیه این باشه:

                    feature/login
                   /
develop ──────────┼──── feature/dashboard
                   \
                    feature/notification

هر توسعه‌دهنده روی Branch خودش کار می‌کنه.

تغییرات تا زمانی که آماده نباشن، وارد develop نمی‌شن.

این یعنی افراد مختلف می‌تونن همزمان روی بخش‌های مختلف پروژه کار کنن، بدون اینکه هر commit مستقیماً روی Branch توسعه تأثیر بذاره.


پس Release کجای داستانه؟

حالا فرض کن چند feature مختلف توسعه پیدا کردن.

مثلاً:

  • Login

  • Dashboard

  • Notification

  • Profile

همه این‌ها وارد develop شدن.

حالا تیم تصمیم می‌گیره نسخه جدید پروژه رو منتشر کنه.

مثلاً:

نسخه 2.0.0

آیا همین الان باید develop رو Merge کنیم داخل main؟

نه لزوماً.

ممکنه هنوز نیاز داشته باشیم:

  • تست‌های نهایی انجام بشن.

  • باگ‌ها برطرف بشن.

  • Version Number تغییر کنه.

  • Changelog آماده بشه.

  • تنظیمات مربوط به انتشار بررسی بشن.

  • آخرین بررسی‌های مربوط به production انجام بشه.

اینجاست که Release Branch وارد داستان میشه.


Release Branch چیست؟

Release Branch برای زمانی استفاده میشه که توسعه نسخه جدید تقریباً تموم شده و می‌خوایم اون رو برای انتشار آماده کنیم.

برای آماده کردن یک نسخه جدید، از develop یک Branch جدید می‌سازیم:

git checkout develop
git checkout -b release/2.0.0

حالا:

develop
   │
   └── release/2.0.0

از اینجا به بعد، تمرکز این Branch روی آماده کردن نسخه 2.0.0 هست.

مثلاً اگر یک باگ کوچیک پیدا بشه، می‌تونیم همین‌جا برطرفش کنیم.

اما قرار نیست در این مرحله featureهای کاملاً جدید و بزرگ اضافه کنیم.

چون هدف از Release Branch اینه که نسخه‌ای که قبلاً توسعه پیدا کرده رو تثبیت و برای انتشار آماده کنیم، نه اینکه قابلیت‌های جدید و بزرگ به اون اضافه کنیم.


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

فرض کن تست‌های نهایی انجام شده و نسخه 2.0.0 آماده است.

حالا Release Branch باید وارد main بشه.

git checkout main
git merge release/2.0.0

حالا main شامل نسخه‌ایه که آماده انتشار شده.

در Git Flow کلاسیک، معمولاً نسخه منتشرشده رو با یک Tag هم مشخص می‌کنیم:

git tag v2.0.0
git push origin v2.0.0

Tag باعث میشه بتونیم دقیقاً مشخص کنیم کدوم commit مربوط به نسخه 2.0.0 بوده.

مثلاً اگه چند ماه بعد بخوایم وضعیت نسخه 2.0.0 رو بررسی کنیم، می‌تونیم به همون Tag مراجعه کنیم.

اما کار هنوز تمام نشده.

ممکنه در Release Branch تغییراتی انجام داده باشیم که در develop وجود ندارن.

مثلاً یک باگ کوچیک رو در مرحله release برطرف کردیم.

پس باید این تغییرات رو به develop هم برگردونیم:

git checkout develop
git merge release/2.0.0

چرا؟

چون نمی‌خوایم اصلاحاتی که هنگام آماده‌سازی release انجام دادیم، فقط داخل main باقی بمونن.

بعد از اینکه Release Branch در هر دو مسیر Merge شد، معمولاً می‌تونیم اون رو حذف کنیم:

git branch -d release/2.0.0

در نتیجه جریان کلی چیزی شبیه اینه:

develop
   │
   ▼
release/2.0.0
   │
   ├──────────► main
   │
   └──────────► develop

اما یک مشکل فوری داریم!

فرض کن چند روز از انتشار نسخه 2.0.0 گذشته.

یک کاربر گزارش میده که در production، هنگام پرداخت سفارش یک باگ جدی وجود داره.

تیم هم در حال توسعه نسخه 2.1.0 روی develop هست.

آیا باید باگ رو روی develop برطرف کنیم و بعد منتظر انتشار نسخه بعدی بمونیم؟

نه.

این باگ همین الان روی نسخه production وجود داره.

اینجاست که Hotfix Branch وارد داستان میشه.


Hotfix چیست؟

Hotfix برای زمانی استفاده میشه که یک مشکل فوری در نسخه production پیدا شده و باید بدون منتظر موندن برای release بعدی برطرف بشه.

برای رفع یک مشکل فوری در نسخه منتشرشده، از main یک Branch جدید می‌سازیم:

git checkout main
git checkout -b hotfix/payment-error

حالا:

main
 │
 └── hotfix/payment-error

باگ رو برطرف می‌کنیم، تست‌ها رو اجرا می‌کنیم و بعد Hotfix رو وارد main می‌کنیم:

git checkout main
git merge hotfix/payment-error

حالا می‌تونیم نسخه جدیدی منتشر کنیم.

مثلاً:

v2.0.1

برای مشخص کردن این نسخه هم Tag ایجاد می‌کنیم:

git tag v2.0.1
git push origin v2.0.1

اما یک کار دیگه هم باید انجام بدیم.

تغییر Hotfix باید وارد develop هم بشه:

git checkout develop
git merge hotfix/payment-error

چون اگه فقط main رو اصلاح کنیم، این تغییر وارد develop نمیشه و ممکنه همون باگ دوباره در نسخه‌های بعدی برگرده.

پس مسیر Hotfix به شکل زیره:

             ┌──────────► main
hotfix ──────┤
             └──────────► develop

بعد از اینکه Hotfix در هر دو Branch قرار گرفت، می‌تونیم Branch مربوط به اون رو هم حذف کنیم:

git branch -d hotfix/payment-error

ساختار Branchها در یک نگاه

تا اینجا چند نوع Branch رو شناختیم:

main
develop
feature/*
release/*
hotfix/*

اگه بخوایم خیلی خلاصه وظیفه هرکدوم رو ببینیم:

main نسخه پایدار و قابل انتشار پروژه

develop جمع شدن تغییرات نسخه بعدی

feature/* توسعه قابلیت‌های جدید

release/* آماده‌سازی یک نسخه برای انتشار

hotfix/* رفع مشکلات فوری production

پس می‌تونیم هسته Git Flow رو اینطوری در ذهن داشته باشیم:

                         ┌── feature/*
                         │
main ─────────────── develop
  │                      │
  │                      └── release/*
  │
  └── hotfix/*

البته این نمودار مسیر واقعی commitها رو به صورت کامل نمایش نمیده؛ فقط رابطه و نقش کلی Branchها رو نشون میده.


حالا کل جریان را کنار هم ببینیم

featureها از develop ساخته میشن و بعد از تکمیل، دوباره به develop برمی‌گردن.

                    feature/login
                   /
develop ───────────┼──── feature/dashboard
                   \
                    feature/profile

وقتی زمان انتشار نسخه جدید رسید:

develop
   │
   ▼
release/2.0.0
   │
   ├──────────► main
   │
   └──────────► develop

و اگه یک مشکل فوری در production پیدا شد:

main
 │
 └── hotfix/payment-error
       │
       ├──────────► main
       │
       └──────────► develop

همین چند Branch، هسته اصلی Git Flow رو تشکیل میدن.


یک پروژه را از ابتدا تا انتشار دنبال کنیم

حالا بیایم همه چیز رو در قالب یک سناریوی واقعی مرور کنیم.

فرض کن پروژه ما یک فروشگاه اینترنتیه.

نسخه فعلی:

v1.0.0

و main همین نسخه رو نگه می‌داره.

تیم تصمیم گرفته نسخه 1.1.0 رو توسعه بده.

ساختار فعلی:

main
 │
 └── develop

حالا یک نفر روی صفحه پروفایل کار می‌کنه:

git checkout develop
git checkout -b feature/profile

نفر دوم هم روی سیستم تخفیف‌ها کار می‌کنه:

git checkout develop
git checkout -b feature/discount

حالا:

             ┌── feature/profile
             │
develop ─────┤
             │
             └── feature/discount

بعد از چند روز هر دو feature آماده میشن.

از طریق Pull Request وارد develop میشن.

حالا تغییرات نسخه بعدی داخل develop قرار گرفتن.

تیم تصمیم می‌گیره نسخه جدید رو آماده کنه.

پس:

git checkout develop
git checkout -b release/1.1.0

در Release Branch چند باگ کوچیک برطرف میشه.

تست‌های نهایی انجام میشن و نسخه آماده انتشار میشه.

حالا release وارد main میشه:

git checkout main
git merge release/1.1.0

بعد Tag نسخه رو ایجاد می‌کنیم:

git tag v1.1.0
git push origin v1.1.0

حالا تغییرات release رو هم به develop برمی‌گردونیم:

git checkout develop
git merge release/1.1.0

و در نهایت Release Branch رو حذف می‌کنیم:

git branch -d release/1.1.0

حالا پروژه در production نسخه 1.1.0 رو اجرا می‌کنه.

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

از main یک Hotfix می‌سازیم:

git checkout main
git checkout -b hotfix/payment

باگ برطرف میشه و بعد:

git checkout main
git merge hotfix/payment

نسخه جدید:

v1.1.1

رو با Tag مشخص می‌کنیم:

git tag v1.1.1
git push origin v1.1.1

بعد Hotfix رو به develop هم Merge می‌کنیم:

git checkout develop
git merge hotfix/payment

و در نهایت Branch مربوط به Hotfix رو حذف می‌کنیم:

git branch -d hotfix/payment

این چرخه می‌تونه بارها و بارها تکرار بشه.


Git Flow چه مشکلی را حل می‌کند؟

حالا که کل فرآیند رو دیدیم، بهتره برگردیم به سؤال اول مقاله.

چرا اصلاً Git Flow به وجود اومده؟

یکی از مهم‌ترین دلایلش اینه که بین توسعه، آماده‌سازی نسخه و production مرز مشخصی ایجاد کنه.

با این ساختار:

main می‌تونه وضعیت نسخه منتشرشده و production رو نگه داره.

develop محل جمع شدن تغییرات نسخه آینده است.

feature/* برای توسعه قابلیت‌های جدید استفاده میشه.

release/* برای آماده کردن یک نسخه جدید استفاده میشه.

و hotfix/* برای رفع مشکلات فوری Production.

در نتیجه، هر Branch هدف مشخصی داره.

این ساختار می‌تونه به تیم کمک کنه که بدونه:

«این تغییر الان کجای چرخه توسعه قرار داره؟»


چند اشتباه رایج

مثل هر روش دیگه‌ای، استفاده اشتباه از Git Flow هم می‌تونه مشکلات خودش رو ایجاد کنه.

۱. کار کردن مستقیم روی main

یکی از ساده‌ترین اشتباه‌ها اینه که برای راحتی، featureها رو مستقیماً روی main توسعه بدیم.

اگر پروژه تیمی باشه و فرآیند مشخصی برای review و انتشار نداشته باشیم، این کار خیلی زود باعث ایجاد مشکل میشه.

بهتره تغییرات جدید از مسیر Branch مناسب خودشون وارد پروژه بشن.

البته این به معنی ممنوع بودن کار مستقیم روی main در تمام Workflowها نیست.


۲. استفاده از Feature Branch برای مدت خیلی طولانی

Feature Branch قرار نیست ماه‌ها از develop جدا بمونه.

هرچه یک Branch مدت بیشتری مستقل بمونه، احتمال ایجاد Conflict هنگام Merge بیشتر میشه.

اگه یک feature خیلی بزرگه، بهتره اون رو به بخش‌های کوچک‌تر تقسیم کنیم.

این کار باعث میشه Branchها زودتر Merge بشن و احتمال ایجاد Conflict هم کمتر بشه.


۳. اضافه کردن Feature جدید به Release Branch

وقتی Release Branch ساخته شد، هدف اصلی اون آماده کردن نسخه برای انتشاره.

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

feature جدید بهتره در develop توسعه پیدا کنه و در release بعدی منتشر بشه.


۴. فراموش کردن Merge کردن Hotfix به develop

فرض کن باگ رو در main برطرف کردی، اما تغییر رو به develop برنگردوندی.

چند هفته بعد نسخه جدید منتشر میشه و ممکنه همون باگ دوباره در نسخه جدید ظاهر بشه.

پس Hotfix باید بعد از اصلاح production، به Branch توسعه هم برگرده.


۵. نگه داشتن Branchهای قدیمی

بعد از اینکه یک Feature، Release یا Hotfix کامل شد، اگه دیگه به Branch اون نیاز نداریم، بهتره حذفش کنیم.

مثلاً:

git branch -d feature/login

Branchهای زیاد و بلااستفاده می‌تونن پیدا کردن Branchهای فعال رو سخت کنن.

البته حذف Branch به معنی حذف commitهای Merge‌شده از تاریخچه Git نیست.


آیا Git Flow همیشه بهترین انتخاب است؟

اینجا شاید بعد از خوندن مقاله این سؤال برات پیش بیاد:

«پس همه پروژه‌ها باید از Git Flow استفاده کنن؟»

نه.

و اتفاقاً این نکته خیلی مهمه.

Git Flow فقط یکی از روش‌های مدیریت Branchهاست.

برای پروژه‌هایی که Releaseهای مشخص دارن و معمولاً نسخه‌های مختلف رو در بازه‌های مشخص منتشر می‌کنن، Git Flow می‌تونه انتخاب مناسبی باشه.

اما برای پروژه‌هایی که مرتب Deploy میشن، ممکنه این ساختار بیش از اندازه پیچیده باشه.

در چنین پروژه‌هایی روش‌هایی مثل GitHub Flow یا Trunk-Based Development می‌تونن انتخاب ساده‌تری باشن.


Git Flow یا GitHub Flow؟

در GitHub Flow معمولاً ساختار ساده‌تره.

به جای داشتن main و develop و Release و Hotfix، بیشتر کارها حول main و Branchهای موقتی انجام میشن.

مثلاً:

main
 │
 └── feature/login
        │
        ▼
   Pull Request
        │
        ▼
      main

یعنی feature توسعه پیدا می‌کنه، Pull Request ساخته میشه، کد بررسی میشه و بعد وارد main میشه.

اگر پروژه به Continuous Deployment نزدیک باشه، حتی میشه بعد از Merge شدن تغییرات، فرآیند Deploy رو به صورت خودکار انجام داد.

این مدل برای تیم‌هایی که مرتباً تغییرات کوچیک منتشر می‌کنن، می‌تونه بسیار مناسب باشه.

پس نمی‌تونیم بگیم:

Git Flow بهتر از GitHub Flow است.

یا برعکس.

سؤال درست اینه:

کدوم روش با فرآیند توسعه و انتشار پروژه ما سازگارتره؟


Git Flow یا Trunk-Based Development؟

در Trunk-Based Development، توسعه‌دهنده‌ها معمولاً روی Branchهای موقتی و کوتاه کار می‌کنن و تغییراتشون رو در بازه‌های کوتاه وارد یک Branch اصلی، یا اصطلاحاً Trunk، می‌کنن.

هدف این روش اینه که تغییرات سریع‌تر با هم ترکیب بشن و Branchها برای مدت طولانی از Branch اصلی جدا نمونن.

این روش معمولاً در تیم‌هایی استفاده میشه که فرآیند Continuous Integration (ادغام مداوم تغییرات) و Continuous Delivery (آماده نگه داشتن پروژه برای انتشار) رو به شکل منظم اجرا می‌کنن.

به زبان ساده، تیم مرتب تغییرات کوچک رو وارد Branch اصلی می‌کنه و سیستم‌های تست و انتشار هم کمک می‌کنن که این تغییرات سریع بررسی و آماده انتشار بشن.

اما برای پروژه‌ای که Releaseهای مشخص، نسخه‌بندی رسمی و فرآیند انتشار مرحله‌ای داره، Git Flow ممکنه ساختار واضح‌تری ایجاد کنه.

باز هم یک جواب واحد برای همه پروژه‌ها وجود نداره.


پس کدام را انتخاب کنیم؟

اگر پروژه‌ای داری که:

  • Releaseهای مشخص و نسبتاً رسمی داره.

  • چند Feature همزمان توسعه داده میشن.

  • بین نسخه توسعه و نسخه production تفاوت مشخصی وجود داره.

  • نیاز داری فرآیند Release رو جداگانه مدیریت کنی.

  • گاهی Hotfix فوری برای نسخه production داری.

Git Flow می‌تونه انتخاب مناسبی باشه.

اما اگر:

  • مرتب Deploy می‌کنی.

  • Featureها کوچک هستن.

  • تیم کوچیکه.

  • می‌خوای ساختار Branchها ساده باشه.

  • تغییرات خیلی سریع وارد Production میشن.

احتمالاً GitHub Flow یا یک مدل ساده‌تر انتخاب بهتریه.

در نهایت، قرار نیست Branchهای بیشتری داشته باشیم فقط برای اینکه پروژه حرفه‌ای‌تر به نظر برسه.

هدف Git Flow اینه که مدیریت تغییرات پروژه قابل پیش‌بینی‌تر و منظم‌تر بشه.


یک نکته مهم درباره Git Flow

Git Flow در ابتدا توسط Vincent Driessen معرفی شد و برای سال‌ها یکی از شناخته‌شده‌ترین روش‌های مدیریت Branch در Git بود.

اما دنیای توسعه نرم‌افزار تغییر کرده.

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

در این روش‌ها معمولاً مفاهیمی مثل Continuous Integration (ادغام مداوم تغییرات)، Continuous Delivery (آماده نگه داشتن پروژه برای انتشار) و Continuous Deployment (انتشار خودکار تغییرات) استفاده میشن.

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

به همین دلیل Git Flow رو نباید به عنوان یک قانون همیشگی در نظر بگیریم.

بهتره اون رو به عنوان یکی از روش‌های مدیریت فرآیند توسعه ببینیم.

ممکنه برای یک پروژه عالی باشه و برای پروژه‌ای دیگه فقط پیچیدگی اضافه ایجاد کنه.


یک نکته درباره Git Flow کلاسیک

چیزی که در این مقاله دیدیم، نسخه کلاسیک Git Flow بود.

یعنی ساختاری شامل:

main
develop
feature/*
release/*
hotfix/*

اما Git Flow یک قانون رسمی و اجباری در خود Git نیست.

Git فقط ابزار کنترل نسخه است.

Git Flow یک روش برای مدیریت فرآیند توسعه است که روی Git استفاده میشه.

پس اگر پروژه‌ای داری که به همه این Branchها نیاز نداره، لازم نیست صرفاً به خاطر اسم Git Flow همه اون‌ها رو ایجاد کنی.

ممکنه یک پروژه فقط به این ساختار نیاز داشته باشه:

main
 │
 └── feature/*

و یک پروژه دیگه واقعاً به:

main
develop
feature/*
release/*
hotfix/*

نیاز داشته باشه.

مهم اینه که Workflow به جای ایجاد پیچیدگی، یک مشکل واقعی رو حل کنه.


حرف آخر

در این مقاله با Git Flow آشنا شدیم و دیدیم چطور میشه با استفاده از Branchهای مختلف، فرآیند توسعه و انتشار یک پروژه رو مدیریت کرد.

یاد گرفتیم که:

main برای نسخه پایدار و قابل انتشار پروژه است.

develop محل جمع شدن تغییرات در حال توسعه است.

feature/* برای توسعه قابلیت‌های جدید استفاده میشه.

release/* برای آماده‌سازی یک نسخه جدید ساخته میشه.

و hotfix/* برای رفع مشکلات فوری Production استفاده میشه.

همچنین دیدیم که Pull Request می‌تونه قبل از Merge شدن تغییرات، امکان Code Review و اجرای تست‌ها رو فراهم کنه.

با Release Branch یاد گرفتیم که میشه مرحله آماده‌سازی نسخه رو از توسعه Featureهای جدید جدا کرد.

و با Hotfix دیدیم که چطور میشه یک مشکل فوری production رو بدون متوقف کردن توسعه نسخه بعدی برطرف کرد.

اما مهم‌تر از همه فهمیدیم که هدف Git Flow، زیاد کردن تعداد Branchهای پروژه نیست.

هدف اینه که هر تغییر، مسیر مشخص خودش رو داشته باشه.

وقتی چند نفر همزمان روی یک پروژه کار می‌کنن، داشتن یک فرآیند مشخص می‌تونه جلوی خیلی از مشکلات رو بگیره.

اما در نهایت:

بهترین Workflow، پیچیده‌ترین Workflow نیست؛ روشی است که با نیازهای واقعی پروژه شما هماهنگ باشد.

پس قبل از اینکه Git Flow رو وارد پروژه کنی، اول به فرآیند توسعه، اندازه تیم، نحوه انتشار و سرعت Deploy پروژه نگاه کن.

ممکنه Git Flow دقیقاً چیزی باشه که بهش نیاز داری.

و ممکنه یک Workflow ساده‌تر، انتخاب بهتری باشه.

اگر جایی سوالی داری، نکته‌ای به ذهنت رسید، یا حتی اگه فکر می‌کنی یه قسمتی از این مقاله رو میشه بهتر نوشت، حتماً تو نظرات بهم بگو.

همه با هم یاد می‌گیریم! 🙏

ارسال دیدگاه

دیدگاه و یا پرسش خود را برای ما ارسال کنید.

وارد شوید

برای ارسال دیدگاه یا پرسش خود ابتدا وارد سایت شوید

ورود یا ثبت نام

دیدگاه کاربران

هنوز دیدگاه یا پرسشی ایجاد نشده است :/

تازه‌ترین نوشته‌ها

دیدن همه

تجربه‌ها، دیدگاه‌ها و نکات الهام‌بخشی که با شما به اشتراک می‌گذاریم.