مفاهیم مقدماتی Git Merge و Git Rebase – به زبان ساده


همه ما به عنوان توسعهدهنده باید بین Merge و Rebase انتخاب کنیم. ما با همه ارجاعهایی که از اینترنت دریافت کردیم، ممکن است بر این باور باشیم که «از Rebase استفاده نکنید، چون باعث بروز مشکلات جدی میشود». در این نوشته به توضیح تفاوت بین Merge و Rebase میپردازیم و توضیح میدهیم که چرا باید از آنها استفاده کنیم یا نکنیم و این که چگونه از آنها استفاده کنیم.
Git Merge و Git Rebase هدف یکسانی دارند. این دو ابزار برای یکپارچهسازی تغییرات از شاخههای مختلف در یک قالب واحد طراحی شدهاند. با این که هدف نهایی آنها یکسان است؛ اما این دو متد به روشهای متفاوتی این کار را انجام میدهند.
این بحث باعث شده است که جامعه Git به دو دسته تقسیم شود. برخی بر این باور هستند که همواره باید از rebase استفاده کرد، و برخی دیگر نیز فکر میکنند که باید همیشه merge را مورد استفاده قرار داد. هر یک برخی مزیتهای اقناعکننده دارد.
Git Merge
ادغام کردن یک رویه رایج برای توسعهدهندههایی است که از سیستمهای کنترل نسخه گیت استفاده میکنند. چه شاخهها برای تست کردن ایجاد شده باشند و چه برای اصلاح خطا یا دلایل دیگر، ادغام کردن کامیتها باعث تغییر مکان آنها میشود. به بیان دقیقتر، ادغام کردن باعث میشود که محتوای شاخه مبدأ را برداریم و با شاخه مقصد یکپارچه کنیم. در این فرایند تنها شاخه مقصد تغییر مییابد و سابقه شاخه مبدأ دست نخورده باقی میماند.
مزایای Merge
- ساده و آشنا است.
- سابقه کامل و ترتیب زمانی را حفظ میکند.
- چارچوب شاخه را حفظ میکند.
معایب
- سابقه کامیت میتواند به دلیل وجود تعداد زیادی از کامیت های merge آلوده شود.
- دیباگ کردن با استفاده از fit biscet میتواند دشوارتر باشد.
شیوه اجرای Git Merge
ادغام شاخه master در شاخه feature با استفاده از دستورهای checkout و merge صورت میگیرد.
$ git checkout feature $ git merge master (or) $ git merge master feature
این امر موجب میشود که یک «Merge commit» جدید در شاخه Merge commit ایجاد شود و سابقه هر دو شاخه را نگهداری میکند.
Git Rebase
Rebase روش دیگری برای یکپارچهسازی تغییرات یک شاخه در شاخه دیگر است. Git Rebase همه تغییرات را در یک وصله (patch) منفرد فشرده میکند و سپس آن وصله را در شاخه مقصد ادغام میکند.
Rebase کردن برخلاف merge کردن، باعث از بین رفتن سابقه تغییرات میشود، زیرا کل کار را از یک شاخه به شاخه دیگر انتقال میدهد. در این فرایند سابقه شاخه، ناخواسته حذف میشود.
در واقع Rebase به شیوه ارسال تغییرات از سلسله مراتب بالاتر به بخشهای پایینتر و merge نیز گردش تغییرات از پایین رو به بالا گفته میشود.
مزایای Rebase
- باعث منظم شدن یک سابقه بالقوه پیچیده میشود.
- دستکاری یک کامیت منفرد آسانتر است.
- از ایجاد نویز کامیت در ریپوهای شلوغ با شاخههای زیاد جلوگیری میکند.
- کامیت های میانی از طریق تبدیل شدن به یک کامیت منفرد پاک میشوند که برای تیمهای DevOps بسیار مفید است.
معایب
- تجزیه کردن یک feature به تعدادی از کامیتها میتواند موجب از بین رفتن چارچوب کار شود.
- Rebase کردن یک ریپازیتوری عمومی در موارد کار تیمی میتواند کار خطرناکی باشد.
- استفاده از Rebase برای بهروز نگه داشتن شاخه feature همواره به کار بیشتری نیاز دارد.
- Rebase کردن در شاخههای ریموت نیازمند force push است. بزرگترین مشکلی که افراد با آن مواجه هستند این است که از force push استفاده میکنند؛ اما git push را به عنوان پیشفرض تنظیم نکردهاند. این امر موجب میشود که همه شاخههایی که نام مشابهی دارند، چه به صورت محلی و چه ریموت، بهروزرسانی شوند و این وضعیت نامناسبی است.
- اگر به طرز نادرستی Rebase کنید و ناخواسته کل سابقه را بازنویسی کنید، میتواند منجر به مشکلات جدی شود و از این رو باید مطمئن شوید که میدانید دقیقاً چه کاری انجام میدهید.
چگونه Rebase را اجرا کنیم؟
Reabse کردن شاخه feature در شاخه master با استفاده از دستورهای زیر ممکن است:
$ git checkout feature $ git rebase master
این کار باعث میشود که کل شاخه feature روی شاخه master منتقل شود. این کار از طریق بازنویسی سابقه پروژه با ایجاد کامیتهای تازه برای هر کامیت در شاخه اصلی (master ) صورت میگیرد.
Rebase کردن به شیوه تعاملی
این وضعیت امکان تغییر دادن کامیتها در هنگام انتقالشان به شاخه جدید را فراهم میکند. این وضعیت قویتر از rebase خودکار است، چون کنترل کاملی روی سابقه کامیت شاخه ارائه میکند. به طور معمول از این روش برای پاکسازی یک سابقه شلوغ، پیش از ادغام شاخه feature در master استفاده میشود.
$ git checkout feature $ git rebase -i master
دستورهای فوق باعث باز شدن ویرایشگر میشود و همه کامیتهایی که باید منتقل شوند، فهرست میشوند.
pick 22d6d7c Commit message#1 pick 44e8a9b Commit message#2 pick 79f1d2h Commit message#3
بدین ترتیب دقیقاً حالتی که شاخه پس از اجرای rebase به نظر میرسد را مشاهده میکنیم. با تغییر ترتیب موجودیتها میتوان شیوه نمایش سابقه را به هر صورتی که مورد نظر است تغییر داد. برای نمونه میتوان از دستورهایی مانند fixup, squash, edit و غیره به جای pick استفاده کرد.
از کدام یک باید استفاده کرد؟
شاید اکنون میپرسید که با در نظر گرفتن همه موارد فوق باید از کدام یک استفاده کنیم؟ البته تعمیم و تصمیمگیری در مورد یکی از دو مورد فوق کار دشواری است، چون هر تیم شرایط متفاوتی دارد؛ اما به هر حال باید یک چنین تصمیمی گرفته شود.
تیمهای توسعه باید چند بحث را هنگام تصمیمگیری در مورد rebase یا merge در نظر بگیرند. چون چنان که مشخص شد یک راهبرد گردش کار بر دیگری ارجحیت ندارد و به تیمهای کاری بستگی دارد.
باید سطح rebase کردن و سواد Git در سراسر سازمان ارزیابی شود. همچنین باید در مورد درجهای که به سادگی rebase کردن در مقایسه با قابلیت ردگیری سابقه merge ها اهمیت میدهید، توجه کنید.
در نهایت تصمیمگیری در مورد استفاده از merge یا rebase باید در چارچوب یک راهبرد روشن شاخه سازی (branching) در نظر گرفته شود. یک راهبرد موفق برای شاخه سازی پیرامون ماهیت سازمان و تیمها طراحی میشود.
با رشد کردن تیمها، مدیریت یا ردگیری تغییرات توسعه با سیاست استفاده همیشگی از merge، دشوارتر میشود. برای این که سابقه تمیز و قابل درکی از کامیتها وجود داشته باشد، باید از rebase استفاده کرد که معقول و کارآمد است. با در نظر گرفتن شرایط و راهنماییهای زیر میتوانید بیشترین بهره را از rebase بگیرید:
اگر به صورت محلی توسعه میدهید:
اگر کار خود را با هیچ گس دیگری به اشتراک نمیگذارید، در این مرحله احتمالاً rebase را به merge ترجیح میدهید تا سابقه کارتان تمیز بماند. اگر روی فورک شخصی خود از یک ریپازیتوری کار میکنید و این فورک با هیچ توسعهدهنده دیگری به اشتراک گذاشته نمیشود، بهتر است حتی پس از پوش کردن به شاخه، از rebase استفاده کنید.
اگر کد شما آماده بررسی است:
فرض کنید یک درخواست pull ایجاد کردهاید و دیگران مشغول مرور کردن کار شما هستند و به طور بالقوه قرار است آن را برای مرور محلی در فورک خودشان fetch کنند. در این مرحله نباید از rebase در کار خود استفاده کنید. باید کامیت های rework ایجاد کرده و شاخه feature را بهروزرسانی کنید. این امر به ردگیری درخواستهای pull و جلوگیری از خرابی تصادفی سابقه کار کمک میکند.
اگر مرور کد پایان یافته و در شاخه مقصد یکپارچه میشود:
اینک شما آماده هستید که شاخه feature خود را حذف کنید. با این فرض که توسعهدهندههای دیگر از این زمان به بعد دیگر نمیخواهند این تغییرات را fetch-merge کنند، این وظیفه شما است که از سابقه کار خود حفاظت کنید. در این زمان شما میتوانید سابقه کار خود را بازنویسی کنید، کامیتهای اصلی را فشرده کنید و کامیت های «pr rework» و «merge» را به مجموعه کوچکی از کامیتهای متمرکز تبدیل کنید. ایجاد یک merge صریح برای این کامیتها اختیاری است؛ اما ارزشش را دارد. این کامیت زمانی که feature به master تبدیل میشود ثبت خواهد شد.
سخن پایانی
امیدواریم این نوشته بینشهایی در خصوص Git merge و Git rebase در اختیار شما قرار داده باشد. راهبرد merge در برابر rebase همواره موضوع نزاع بوده است. اما احتمالاً این مقاله به رفع شک و تردیدها کمک میکند و باعث میشود که بتوانید یک رویکرد مناسب برای تیم کاری خود انتخاب کنید.
اگر این مطلب برایتان مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- آموزش گیت (Git) برای مدیریت نسخه توزیع شده
- مجموعه آموزشهای ابزارها و راهکارهای مدیریت وبسایتها
- راهنمای پیشرفته Git برای مبتدیان — به زبان ساده
- چگونه از گیت (Git) به طرز موثرتری استفاده کنیم؟ — به زبان ساده
==
عالی بود
توضیحات ملموس نیست ، انگار بیشتر ترجمه است تا توضیح. کاش طوری توضیح بدید که بار اول مخاطب متوجه بشه