آموزش

rebase در برابر merge؛ کِی از کدام استفاده کنیم

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

تحریریه‌ی دینا کد
نویسنده
۴ دقیقه مطالعه۰ بازدید
اشتراک گذاری۰

جواب کوتاه: روی شاخه‌ای که هنوز push نکرده‌اید یا کسی دیگر رویش کار نمی‌کند، rebase بزنید تا تاریخچه صاف بماند؛ روی شاخه‌ای که با بقیه مشترک است، فقط merge بزنید. تفاوتشان در همین یک چیز است: rebase کامیت‌های شما را دوباره می‌سازد؛ merge هیچ کامیتی را دست نمی‌زند.

یک تاریخچه‌ی واقعی

دو شاخه از یک نقطه جدا شده‌اند: main یک کامیت مستندات دارد، feature دو کامیت کد دارد.

bash$ git log --oneline --graph --all
* adf18c4 به‌روزرسانی مستندات
| * 96ec6ca افزودن logout
| * 2f9bf5a افزودن login
|/
* 1d1e831 کامیت پایه

merge: هر دو تاریخچه کنار هم می‌مانند

bash$ git checkout feature
$ git merge main
*   cbcd8a8 Merge branch 'main' into feature
|| * adf18c4 به‌روزرسانی مستندات
* | 96ec6ca افزودن logout
* | 2f9bf5a افزودن login
|/
* 1d1e831 کامیت پایه

یک کامیت جدید (cbcd8a8) با دو والد ساخته شد. کامیت‌های login و logout دقیقاً همان هش قبلی را دارند — هیچ‌چیزی بازنویسی نشده، فقط یک نقطه‌ی اتصال اضافه شده.

rebase: تاریخچه صاف می‌شود، ولی کامیت‌ها عوض می‌شوند

bash$ git checkout feature
$ git rebase main
* 1045314 افزودن logout
* dca4a16 افزودن login
* 25505c8 به‌روزرسانی مستندات
* 1d1e831 کامیت پایه

نتیجه یک خط راست است — انگار از اول روی main کار کرده بودید. ولی نگاه کنید به هش‌ها: login از 2f9bf5a شد dca4a16، logout از 96ec6ca شد 1045314. این‌ها کامیت‌های جدیداند با همان محتوا؛ کامیت‌های قبلی دیگر روی این شاخه نیستند.

چرا همین تفاوت، قانونِ «rebase نزن روی شاخه‌ی push‌شده» را می‌سازد

چون هش عوض شده، اگر همین شاخه را قبلاً push کرده باشید، push دوباره‌ی معمولی رد می‌شود:

bash$ git push origin feature
error: failed to push some refs to '...'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.

گیت فکر می‌کند شاخه‌ی remote از شاخه‌ی شما جلوتر است — چون کامیت‌های قدیمی هنوز آن‌جا هستند و شما دارید یک تاریخچه‌ی متفاوت با همان اسم می‌فرستید. تنها راه، push --force (یا امن‌ترش، --force-with-lease) است — و اگر همکارتان همان کامیت‌های قدیمی را pull کرده باشد، کارش روی تاریخچه‌ای می‌ماند که دیگر وجود ندارد.

قانون عملی

وضعیت انتخاب
شاخه‌ی شخصی، هنوز push نشده rebase — تاریخچه‌ی تمیزتر
شاخه‌ای که دیگران هم رویش کار می‌کنند فقط merge
می‌خواهید commit-by-commit مرور کنید rebase قبل از باز کردن PR
مطمئن نیستید کسی دیگر pull کرده یا نه merge — همیشه امن است

اگر مطمئن نیستید، merge بزنید. یک کامیت merge اضافه در تاریخچه، خیلی کمتر از یک تاریخچه‌ی بازنویسی‌شده روی شاخه‌ی مشترک هزینه دارد.

اگر می‌خواهید کار تیمی روی گیت‌هاب — شاخه، pull request، حل تعارض — را با پروژه‌ی واقعی تمرین کنید، دوره‌ی گیت و گیت‌هاب دقیقاً همین سناریوها را چند بار زیر دستتان می‌برد.

تحریریه‌ی دینا کد
نویسنده

نظرها

اولین نفری باشید که نظر می‌دهد
برای ثبت نظر وارد شوید

سؤالتان را بپرسید یا تجربه‌تان را بنویسید — نویسنده‌ی مطلب پاسخ می‌دهد.

مطالب مرتبط

از همین دسته
آموزش

چرا Rust به‌جای segfault، خطای کامپایل می‌دهد

در C یا ++C یک اشاره‌گر نامعتبر معمولاً ماه‌ها بعد، در پروداکشن، خودش را نشان می‌دهد. در Rust همان اشتباه، همان لحظه‌ی کامپایل متوقفت می‌کند.

تحریریه‌ی دینا کد۵ دقیقه
تفاوت git rebase و git merge؛ کِی از کدام — دینا کد