به فرآیند ترکیب کامیتهای یک شاخه با شاخه دیگر ترکیب شاخه ها یا merge گفته میشود. راه های بسیاری برای ترکیب شاخه ها وجود دارند اما هدف همه آنها به اشتراک گذاری اطلاعات بین شاخه های گوناگون میباشد. که به همین دلیل ترکیب شاخه ها یکی از مهمترین قابلیتهای Git میباشد.
دو روش رایج برای ترکیب شاخه های وجود دارند با نامهای:
- Fast-Forward merge
- 3-Way merge
در هر دو این روشها از فرمان git merge استفاده میشود. اما متد مورد استفاده برای ترکیب شاخه ها به صورت خودکار از روی ساختار تاریخچه پروژه و شاخه های آن تعیین خواهد شد. در هر دو روش شاخه فرعی که قرار است به شاخه اصلی یا هدف الصاق شود باید checked out شده باشد و شاخه اصلی بدون تغییر باقی خواهد ماند. در ادامه به بررسی دو سناریو موجود برای ترکیب شاخه ها با فرمان زیر میپردازیم:
git checkout master git merge some-feature
همانطور که اشاره شد اجرای دو فرمان بالا باعث میشود که شاخه some-feature به شاخه اصلی یا master اضافه شود. بیشتر اوقات شما زمانی این فرمان ها را اجرا میکنید که یک بخش از پروژه را تکمیل کرده اید و میخواهید به نسخه اصلی پروژه آنرا اضافه کنید.
Fast-Forward Merge
سناریوی اول به صورت زیر میباشد:
در این سناریو ما یک شاخه جدید ایجاد کرده ایم تا یک قابلیت جدید به پروژه اضافه کنیم و دو کامیت در این شاخه جدید ثبت کرده ایم و الان آماده ایم که قابلیت جدید کد نویسی شده به شاخه اصلی پروژه اضافه شود. به جای اینکه دو کامیت شاخه را دوباره در شاخه اصلی ایجاد شوند Git اشاره گر شاخه master را به ابتدای شاخه some-feature میبرد. مانند شکل زیر:
بعد از عمل ترکیب شاخه master در بر دارنده تمامی تاریخچه پروژه میباشد و شاخه فرعی میتواند پاک شود مگر اینکه شما همچنان بخواهید بر روی شاخه فرعی کار کنید. این ساده ترین حالت ترکیب شاخه ها در Git میباشد.
شاید این سوال در ذهن ایجاد شود که چرا از اول دو کامیت شاخه فرعی را در شاخه اصلی ثبت نکردیم؟ علت این هست که با ایجاد شاخه جدید شما یک محیط امن برای توسعه کد نویسی قابلیتهای جدید پروژه ایجاد کرده اید که اگر تلاشهای شما به نتیجه نرسند نیازی نیست که کل پروژه را به عقب برگردانید و تنها کافی است که شاخه جدید حاوی کدهای ناتمام و اشتباه را پاک کنید.
3-Way Merge
همیشه ترکیبها به سادگی مثال قبل نیستند. به یاد داشته باشید که مزیت اصلی شاخه ها در Git قابلیت توسعه و کد نویسی بخشهای مختلف پروژه به صورت موازی میباشد. به همین خاطر بیشتر اوقات به سناریوی زیر برخورد میکنیم:
این سناریو مانند سناریو Fast-Forward شروع شد اما در حین تکمیل شاخه فرعی یک یا چند کامیت جدید به شاخه اصلی اضافه شده است. در چنین موقعیتی عمل ترکیب شاخه فرعی با اصلی را ترکیب سه طرفه مینامند که با همان دستورات ترکیب Fast-Forward پیاده سازی میشود.
همانطور که در تصویر مشاهده میکنید Git نمیتواند از روش Fast-Forward به دلیل کامیت ثبت شده در شاخه اصلی بعد از ایجاد شاخه فرعی استفاده کند. لذا Git یک کامیت ترکیبی جدید که در بر دارنده snapshot از هر دو شاخه میباشد ایجاد میکند. توجه داشته باشید که این کامیت ترکیبی جدید دو ریشه دارد و دسترسی به تاریخچه هر دو شاخه نیز دارد و اگر بعد از این ترکیب فرمان git log را اجرا کنید فهرست کامیتهای هر دو شاخه را خواهید دید.
مغایرت در ترکیب
زمانی که شما میخواهید دو شاخه مختلف که هر یک تغییراتی بر روی یک قسمت کد ایجاد کرده اند، را با هم ترکیب کنید Git نمیتواند تشخیص دهد که تغییرات اعمال شده کدام شاخه را به شاخه اصلی اضافه کند که به این وضعیت مغایرت در ترکیب یا merge conflicts گفته میشود. مطمئناً این وضعیت در حین ترکیب Fast-Forward بوجود نخواهد آمد. زمانی که Git با مغایرت مواجه می شود پیغام زیر را نمایش میدهد:
Auto-merging index.html
CONFLICT (content): Merge conflict in
Automatic merge failed; fix conflicts and then commit
the result.
به جای اینکه به صورت خودکار کامیت ها ترکیب شوند Git صبر میکند و از شما میپرسد که چه کار کند. با اجرای فرمان git status در این سناریو خروجی مشابه زیر خواهد داشت:
# On branch master
# Unmerged paths:
#
# both modified: <file>
تمامی فایلهایی که توسط دو یا چند شاخه تغییر کرده اند در بخش Unmerged paths قرار میگیرند. همچنین git محتوای آنها را نمایش میدهد:
<<<<<<< HEAD
This content is from the current branch.
=======
This is a conflicting change from another branch.
>>>>>>> some-feature
بخش قبل از ======= مربوط به شاخه master میباشد و الباقی مربوط به شاخه هایست که میخواهید با شاخه اصلی ترکیب کنید. برای حل مشکل بخشهای <<<<<< و ======== و <<<<<<<< اضافه شده توسط git را از فایل پاک کنید و نسخه ای از فایل را که میخواهید در ترکیب از آن استفاده کنید را نگه دارید و سپس با فرمان git add به git فرمان بدهید که مشکل را حل کرده اید.
اگر از پروژه پس از حل مشکل confilict و ترکیب شاخه ها log بگیرید در خروجی فرمان log تمامی confilict های گذشته نیز فهرست خواهند شد که در برخی موارد کمک به پیدا کردن ریشه مشکل در پروژه خواهد کرد.