راهنمای گام به گام تغییر پایه یک شاخه مبتنی بر شاخه دیگر در گیت پس از Squash Merge

در گیت، تغییر دادن پایهٔ شاخه‌ای که بر پایه شاخه‌ای دیگر بنا شده است پس از Squash Merge می‌تواند دشواری‌هایی داشته باشد. در این مقاله به صورت گام به گام این مشکل را رفع می‌کنیم.

مساله چیست؟

پیش و پس از تغییر پایه

روی پروژه‌ای که از گیت به عنوان سامانه کنترل نسخه استفاده می‌کند یک شاخه main داریم (که شاخه اصلی پروژه است. روی main، شاخهٔ آبی را ساخته‌ایم و پس از مدتی، بر پایه این شاخه و ویژگی‌هایی که افزوده است، شاخهٔ قرمز ساخته شده است. اکنون، به روش Squash Merge، تغییرات شاخهٔ آبی روی main ادغام شده است. (توجه داشته باشید که بر خلاف ادغام معمولی دو شاخه که منتجر به ایجاد یک commit با دو والد می‌شود، Squash Merge کلیه تغییرات را به صورت یک commit و با یک والد ثبت می‌کند. این مساله با پیکان نقطه‌چین در تصویر نمایش داده شده است.)

اکنون می‌خواهیم پایهٔ شاخهٔ قرمز را از آخرین تغییرات شاخهٔ آبی، به آخرین تغییرات شاخهٔ main تغییر دهیم. هرچند در این مثال ساده، ممکن است ضرورتی نداشته باشد اما تصور کنید شرایط پروژه طوری بوده باشد که در این فاصله، تغییرات جدیدی به main اضافه شده باشد. چه اتفاقی رخ می‌دهد؟

اگر از دستور git rebase master‍ استفاده کنید، چیزی رخ می‌دهد که در نگاه اول عجیب است. تاریخچه شاخهٔ قرمز صرفا شامل b1 و b2 نمی‌شود. چرا؟ چون b1 بر پایهٔ a2 و آن نیز بر پایهٔ a1 بوده است. اما اکنون که می‌خواهیم پایه را به m3 تغییر دهیم، خبری از این دو کامیت نیست. درست است که m3 تغییرات حاصل از آن دو را در خود دارد اما ارجاعی به آن‌ها وجود ندارد. در این حالت، گیت تلاش می‌کند a1 و a2 را هم وارد بازی کند و این کار ممکن است منجر به تعارض یا conflict شود. (فرض کنید شاخهٔ آبی حاوی تغییراتی به مراتب بیشتر از این دو تغییر می‌بود و بعضی از تغییرات برای بازگرداندن تغییرات قبلی بوده باشند).

در این حالت چه باید کرد؟ آیا باید تک تک تعارض‌ها را دستی رفع کنیم؟ که چه بشود؟ اگر آن تغییرات را اکنون در m3 داریم، چرا باید باز کامیت‌های جدید ایجاد کنیم برای همان تغییرات؟ و این، دقیقا مساله‌ای است که در این مقاله می‌خواهیم رفع کنیم.

چه کنیم؟

ما نیاز داریم که حین تغییر پایه، تاریخچه شاخهٔ قرمز را پاک‌سازی کنیم. بگذارید گام به گام پیش برویم:

  1. اگر نخستین باری است که چنین کاری می‌کنید، یک نسخه پشتیبان از شاخهٔ موجود بگیرید. مثلا از git branch --copy red-branch-backup‍ استفاده کنید.
  2. اطمینان حاصل کنید که می‌دانید نخستین تغییر شاخهٔ جاری کدام است. یا شناسهٔ یکتای آن تغییر را به ذهن بسپارید و یا اگر توضیحات کامیت روشن و معنادار است، آن را حفظ کنید.
  3. در حالی که روی شاخهٔ قرمز هستید، دستور git rebase –interactive main` را اجرا کنید. بلافاصله یک پروندهٔ موقت در ویرایش‌گر شما باز می‌شود. این پرونده حاوی فهرستی از تغییری است که قرار است از نقطه پایه مورد استفاده قرار بگیرند. در این جا کارهای مختلفی می‌توانید انجام دهید اما تنها چیزی که ما نیاز داریم این است که تمامی خطوط موجود در فهرست تغییرات را که به شاخهٔ آبی مربوط بوده‌اند (بالاتر از اولین کامیت شاخهٔ قرمز هستند) را پاک کنیم.
  4. حال پرونده را ذخیره کنید. فرایند تغییر پایه شروع شده و تنها کامیت‌هایی که در پرونده باقی ماندند را روی main اعمال می‌کند. اگر تعارضی به واسطه این تغییرات جدید ایجاد نشده باشد، کار تمام است. در غیر این صورت، با همان روش معمول حل تعارض، مشکل را رفع کنید.
  5. تاریخچه را بررسی کنید. اکنون باید بتوانید تنها تغییرات شاخهٔ قرمز را ببینید که بر پایهٔ m3 هستند. البته توجه داشته باشید که شناسه SHA کامیت‌ها عوض شده است. این‌ها، کامیت‌های جدید با تاریخچه جدید هستند.
  6. کار تمام است.

اگر روش بهتری برای رسیدن به این هدف می‌شناسید، لطفا در بخش نظرات با من و دیگران هم‌رسانی کنید.