آموزش گیت پیشرفته: برنچینگ، ریبیس و حل تعارض ها

دواپس و مهندسی سیستم
آموزش گیت پیشرفته: برنچینگ، ریبیس و حل تعارض ها

تقریباً تمامی برنامه نویسان با دستورات اولیه گیت نظیر git add، git commit و git push آشنا هستند. اما هنگامی که اندازه تیم های توسعه از چند نفر به ده ها یا صدها مهندس گسترش می‌یابد و پایپ لاین های استقرار مداوم روزانه ده ها نسخه به پروداکشن ارسال می‌کنند، استفاده سطحی از گیت منجر به آشفتگی در تاریخچه کامیت ها، تعارض های فلج‌کننده (Merge Conflicts) و دشواری در کشف رگرسیون های نرم افزاری می‌شود. تسلط بر گیت پیشرفته (Advanced Git) یکی از ارکان تمایز یک مهندس ارشد نرم افزار است.

همان‌گونه که در راهنمای آموزش داکر تبیین کردیم، مخزن کنترل نسخه (VCS) به عنوان «مرجع یگانه حقیقت» در متدولوژی GitOps عمل می‌کند؛ از این رو حفظ پاکیزگی، یکپارچگی و ردیابی پذیری تاریخچه کامیت ها نقشی بنیادین در پایداری کل چرخه انتشار نرم افزار دارد.

۱. گیت در زیر کاپوت: کالبدشکافی اشیای داخلی در پوشه git.

برخلاف تصور رایج، گیت یک سیستم ذخیره سازی تغییرات خط‌به‌خط (Delta-based) نیست؛ بلکه در هسته خود یک پایگاه داده کلید-مقدار محتوا-محور (Content-Addressable Key-Value Store) است که محتوا را به صورت اسنپ‌شات های نامتغیر در پوشه .git/objects/ با هش SHA-۱ نگه داری می‌کند.

کالبدشکافی معماری داخلی گیت: اشیای Blob، Tree و Commit در دایرکتوری git.
شکل ۱: ساختار گراف غیرمدور جهت‌دار (DAG) در گیت: ارتباط میان اشیای Commit، درخت های پوشه‌ای Tree و باینری های نامتغیر Blob

ارکان سه گانه اشیای گیت

  • اشیای Blob (Binary Large Object): محتوای خالص هر فایل را بدون نگه داری نام فایل یا مجوزها فشرده کرده و ذخیره می‌کند. اگر دو فایل در پوشه های مختلف محتوای یکسانی داشته باشند، تنها یک شیء Blob در دیسک ساخته می‌شود.
  • اشیای Tree: معادل ساختار پوشه ها و دایرکتوری ها هستند. هر Tree جدولی از نام فایل ها، متادیتای دسترسی و پوینتر به شناسه Blob یا Treeهای فرزند را نگه داری می‌کند.
  • اشیای Commit: برچسب زمانی، اطلاعات نویسنده، پیام کامیت و یک پوینتر به شیء Tree ریشه (Root Tree) به همراه پوینتر به کامیت های والد (Parent Commits) را تشکیل می‌دهد.

۲. مقایسه فنی ادغام (Merge) در برابر بازچینی (Rebase)

یکی از داغ‌ترین مباحث در تیم های مهندسی، انتخاب میان استراتژی Merge و Rebase برای همگام سازی شاخه های توسعه با شاخه اصلی است:

مقایسه فنی ادغام (Merge) در برابر بازچینی (Rebase) تاریخچه کامیت ها
شکل ۲: تبارشناسی ادغام شاخه ها: مقایسه کامیت های ادغام سه‌طرفه (Merge Commits) با تاریخچه کاملاً خطی و مستقیم ناشی از Rebase

مزایا و مصالحه های هر رویکرد

معیار ارزیابی دستور git merge دستور git rebase
ساختار گراف تاریخچه شاخه شاخه و غیرخطی با کامیت ادغام (Merge Commit) کاملاً خطی، مرتب و مستقیم (Linear History)
حفظ حقیقت تاریخی دقیقاً توالی زمانی رویدادهای توسعه را حفظ می‌کند کامیت ها را بازنویسی کرده و تاریخچه جدید می‌سازد
حل تعارض ها (Conflicts) تنها یک‌بار در حین ایجاد کامیت ادغام حل می‌شود ممکن است در هر گام از بازپخش کامیت ها نیاز به حل تعارض باشد
قابلیت ردیابی با git bisect دشوارتر به دلیل شاخه های موازی درهم‌تنیده فوق‌العاده ساده، سریع و باینری
قانون طلایی امنیت برای تمام شاخه ها ایمن است هرگز بر روی شاخه های اشتراکی عمومی (مانند main) ریبیس نزنید!

۳. هنر پالایش کامیت ها با ریبیس تعاملی (Interactive Rebase)

در حین پیاده سازی یک ویژگی، طبیعی است که برنامه نویس ده ها کامیت موقت مانند «fix typo»، «wip» یا «fix test» ثبت کند. ارسال چنین پول‌ریکوئستی به پروداکشن یک ضدارزش مهندسی است. با دستور git rebase -i HEAD~N می‌توانید تاریخچه را پیش از مرج به اثری هنری و تمیز تبدیل کنید:

هنر پالایش کامیت ها با ریبیس تعاملی: Squash ،Fixup و Edit
شکل ۳: فرآیند پالایش کامیت های موقت با دستورات pick، squash و fixup برای آماده سازی یک پول‌ریکوئست اتمیک و حرفه‌ای
# فراخوانی ریبیس تعاملی برای ۴ کامیت آخر شاخه
git rebase -i HEAD~4

# در ادیتور بازشده دستورات زیر را تنظیم کنید:
pick 7f3a91c feat(auth): پیاده سازی لاگین با پروتکل OAuth2
squash 3c2d10a fix typo in auth controller
fixup 9a4e81f add unit tests for token validation
reword 4b1c20e docs: بروزرسانی مستندات احراز هویت

۴. استراتژی های برنچینگ: مقایسه Git Flow با توسعه مبتنی بر ترانک (Trunk-Based)

انتخاب استراتژی برنچینگ، سرعت انتشار فیچرهای جدید سازمان را دیکته می‌کند:

استراتژی های برنچینگ: مقایسه کلاسیک Git Flow با مدرن Trunk-Based Development
شکل ۴: مقایسه معماری شاخه ها: تشریفات سنگین Git Flow با شاخه های طولانی در برابر چابکی Trunk-Based با Feature Flags

چرا تیم های مدرن به سمت Trunk-Based مهاجرت کرده اند؟

در مدل سنتی Git Flow، شاخه های متعددی شامل develop, release, hotfix و شاخه های طولانی فیچر وجود دارند که ادغام آن ها در پایان ماه روزها زمان می‌برد و به «جهنم ادغام» مشهور است. در نقطه مقابل، در Trunk-Based Development:

  • تمامی توسعه دهندگان بر روی شاخه های فیچر بسیار کوتاه‌عمر (کمتر از ۱ تا ۲ روز) کار می‌کنند.
  • کدها به طور روزانه با شاخه main ادغام می‌شوند.
  • قابلیت های ناتمام با استفاده از فلگ های ویژگی (Feature Flags) در پروداکشن مخفی می‌مانند تا از تاخیر در بیلد جلوگیری شود.

۵. شکار باگ ها با الگوریتم جستجوی باینری: جادوی git bisect

تصور کنید متوجه شده‌اید قابلیتی که هفته گذشته به درستی کار می‌کرد، اکنون دچار شکست شده است و در این مدت بیش از ۵۰۰ کامیت ثبت شده است. بررسی تک‌تک کامیت ها غیرممکن است. ابزار git bisect با استفاده از الگوریتم جستجوی باینری \(O(\log N)\) در کمتر از ۱۰ مرحله کامیت مقصر را شناسایی می‌کند:

ردیابی باینری باگ ها در تاریخچه با استفاده از دستور git bisect
شکل ۵: ردیابی باینری رگرسیون های نرم افزاری با git bisect: تنصیف لگاریتمی بازه کامیت ها میان نقطه سالم و نقطه خراب
# آغاز فرآیند خطایابی باینری
git bisect start

# علامت‌گذاری کامیت کنونی به عنوان نقطه خراب
git bisect bad

# علامت‌گذاری کامیت دو هفته قبل به عنوان نقطه سالم
git bisect good v1.4.0

# اتوماسیون کامل تست با اجرای اسکریپت تستی در هر گام!
git bisect run pytest tests/test_payment.py

نتیجه گیری و چک لیست حرفه ای گیت

کنترل نسخه تنها یک ابزار پشتیبان‌گیری از کد نیست؛ بلکه فرهنگ همکاری و تاریخچه ثبت تصمیمات مهندسی سازمان شماست. با رعایت این اصول:

  • پیش از ایجاد پول‌ریکوئست، شاخه خود را با Rebase بر روی آخرین وضعیت main همگام سازید.
  • کامیت های آشفته موقت را با Interactive Rebase در قالب کامیت های اتمیک (Atomic Commits) تجمیع کنید.
  • از پیام های استاندارد Conventional Commits (مانند feat:, fix:, refactor:) استفاده کنید.
  • برای کشف رگرسیون های ناشناخته، همواره از قدرت شگفت‌انگیز git bisect کمک بگیرید.

امتیاز و نظرات

۰.۰ (۰ نظر)
برای ثبت دیدگاه باید وارد حساب کاربری شوید. ورود

هنوز نظری ثبت نشده است. اولین نفر باشید.