سمت تاریک ادغام git

تغییر پایه و ادغام
هنگامی که صحبت از مدیریت تغییرات در یک مخزن Git می شود، دو مورد از رایج ترین دستورات مورد استفاده هستند git merge
و git rebase
. اینها هستند دو راه برای حل یک مشکل – ادغام تغییرات از یک شاخه به شاخه دیگر.
در حالی که هر دو دستور برای ترکیب تغییرات استفاده میشوند، اما به روشهای متفاوتی کار میکنند و میتوانند اثرات متفاوتی بر تاریخچه مخزن داشته باشند.
درک تفاوتهای بین git merge و git rebase میتواند به شما کمک کند دستور مناسب برای گردش کار خود را انتخاب کنید و از درگیریها و عوارض احتمالی جلوگیری کنید.
ساده ترین مثال – ادغام سریع به جلو
فرض کنید یک شاخه ویژگی دارید feature
ایجاد شده از master
شاخه، و وجود داشت بدون تغییر جدید در master
شاخه از زمان ایجاد feature
.
$ git init
# ...
$ git commit -m "A1"
$ git switch -c feature
# ...
$ git commit -m "B1"
# the same with B2 and B3
در آن صورت، الف ادغام سریع به جلو می توان برای ادغام تغییرات در feature
به master
. نتیجه یک تاریخچه خطی با تمام تغییرات از feature
در بالای master
، و هیچ تعهد ادغام جدیدی ایجاد نخواهد شد.
$ git switch master
$ git merge feature
Updating 9505fd5.-ae9636f
Fast-forward
همه ادغام ها سریع به جلو نیستند!
این را تصور کنید: شما سخت روی یک ویژگی جدید برای پروژه خود کار کرده اید و تقریباً به پایان رسیده اید. شما تمام تغییرات خود را در یک شاخه جداگانه انجام داده اید، بنابراین تو با استاد دخالت نمیکنی شاخه.
با این حال، درست زمانی که می خواهید همه چیز را جمع بندی کنید، متوجه می شوید شخص دیگری ویژگی جدید خود را ادغام کرده است بدون اینکه به شما بگویم وارد شعبه اصلی شوید.
حالا شما مشکل دارید.
شما نمی توان به سادگی تغییرات شما را ادغام کرد به master با ادغام سریع رو به جلو، زیرا شاخه اصلی دارد تغییر کرد از زمانی که شاخه ویژگی خود را ایجاد کردید.
در عوض، باید از a استفاده کنید ادغام غیر سریع به جلو، که یک تعهد ادغام جدید ایجاد می کند و در صورت همپوشانی تغییرات شما با ویژگی دیگری که در Master ادغام شده است، به طور بالقوه باعث تداخل می شود.
$ git switch master
$ git merge feature
Merge branch 'feature'
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
توجه به این نکته ضروری است ادغام های Git متمرکز بر جلو هستند، یعنی آنها تاریخ موجود را تغییر ندهید به هر طریقی هنگامی که دو شاخه را ادغام می کنید، Git یک commit جدید ایجاد می کند که شامل تغییرات هر دو شاخه می شود، اما commit های موجود در هر شاخه دست نخورده باقی می مانند.
این بدان معنی است که اگر در حین ادغام اشتباه کردید، همیشه می توانید به کامیت های اصلی برگردید و از نو شروع کن
همچنین به این معنی است که می توانید یک شاخه را چندین بار ادغام کنید بدون تغییر تعهدات موجود.
مشکلات ادغام
اگر روی شاخه ویژگی کار می کنید در حالی که سایر اعضای تیم تغییرات را به شاخه اصلی فشار می دهند، مهم است که شعبه خود را با این تغییرات به روز نگه دارید.
یکی از راههای انجام این کار این است که شاخه اصلی را در شاخه ویژگی خود ادغام کنید، که میتواند منجر به چندین تعهد ادغام و تاریخچه ارتکاب بههم ریختگی شود.
ادغام چندین بار شاخه اصلی در شاخه ویژگی می تواند منجر به تعداد قابل توجهی ادغام شود که می تواند پیگیری و درک تاریخچه Git شما را دشوار کند.
$ git checkout feature
$ git merge master
# done multiple times to have feature branch updated
در نتیجه، در نظر گرفتن استراتژی های جایگزین، مانند تغییر پایه یا له کردن متعهد می شود که شما را حفظ کند commit history clean و سازماندهی شده در حالی که هنوز تغییرات از شاخه اصلی را در بر می گیرد.
Rebasing یک گزینه دیگر است
یک جایگزین برای ادغام، تغییر شاخه ویژگی خود به شاخه اصلی است.
طبق مستندات Git، git rebase
دستوری است که برای اعمال تغییرات از یک شاخه به شاخه دیگر استفاده می شود. ایده اصلی این است که تغییراتی را که در یک شاخه ایجاد شده است (به نام شاخه “منبع”) و دوباره آنها را در بالای شاخه دیگر (به نام شاخه “هدف”) پخش کنید. این می تواند زمانی مفید باشد که بخواهید تغییرات ایجاد شده در یک شاخه را در شاخه دیگر، در حالی که a را حفظ کنید، ترکیب کنید تاریخچه پاک و خطی.
را git rebase
دستور با یافتن commit جد مشترک دو شاخه (یعنی نقطه ای که در آن از هم جدا شده اند) کار می کند و سپس یک سری commit جدید ایجاد می کند که تغییرات ایجاد شده در شاخه منبع را در بالای شاخه هدف اعمال می کند. فرآیند شامل مراحل زیر است:
- Git تعهد اجداد مشترک دو شاخه را مشخص می کند.
- Git یک شاخه موقت جدید بر اساس شاخه هدف ایجاد می کند.
- Git تغییرات ایجاد شده در شاخه منبع را یکی یکی به ترتیبی که در ابتدا ایجاد شده اند اعمال می کند.
- Git برای هر یک از تغییرات commit های جدیدی ایجاد می کند و آنها را در شاخه موقت اعمال می کند.
- در نهایت، Git نشانگر شاخه هدف را به commit های جدید منتقل می کند، و به طور موثر تغییرات را از شاخه مبدا ترکیب می کند.
شایان ذکر است که در طول این فرآیند، در صورتی که تغییرات یکسانی در هر دو شاخه مبدا و هدف ایجاد شود، ممکن است تداخل ایجاد شود. در این موارد، Git فرآیند rebase را متوقف میکند و به شما اجازه میدهد تا قبل از ادامه، تضادها را به صورت دستی حل کنید.
ولی…
… یک پتانسیل عیب استفاده از git rebase این است که آن را تاریخ را بازنویسی می کند با حرکت دادن کل شاخه ویژگی برای شروع از نوک شاخه اصلی، که منجر به ایجاد commit های جدید برای هر یک از commit های شاخه ویژگی اصلی می شود.
در حالی که این رویکرد می تواند commit های ادغام را حذف کند و تاریخچه commit را خطی نگه دارد، همچنین می تواند ردیابی تغییرات را دشوار می کند در طول زمان و اگر سایر اعضای تیم در همان شاخه کار کنند، به طور بالقوه باعث درگیری می شود.
$ git switch feature
$ git rebase master
⛔️ هشدار ⛔️
مهم است که از تغییر پایه تعهداتی که با سایر اعضای تیم به اشتراک گذاشته شده است خودداری کنید.
اگر قبلاً commitها را به یک مخزن مشترک فشار دادهاید، معمولاً توصیه نمیشود که تاریخچه را با تغییر پایه آن commitها بازنویسی کنید، زیرا انجام این کار میتواند درگیری ایجاد می کند و درک و پیگیری تغییرات را برای سایر اعضای تیم دشوار می کند.
نتیجه
ادغام
✅ طرفداران
- تاریخچه کاملا قابل ردیابی،
- مبتدی دوستانه،
- زمینه اصلی شاخه منبع را حفظ می کند،
- commit های مربوط به شاخه منبع از سایر تعهدات شاخه جدا می شوند
⛔️ منفی
- تاریخ می تواند به شدت توسط بسیاری از ادغام ها آلوده شود
Rebasing
✅ طرفداران
- تاریخچه کد ساده، خطی و قابل خواندن
- دستکاری یک تاریخچه commit ساده تر از تاریخچه بسیاری از شاخه های ویژگی جداگانه با commit های اضافی است
⛔️ منفی
- کاهش این ویژگی به تعداد انگشت شماری از commit ها می تواند زمینه را پنهان کند
- هنگام استفاده از rebasing نسبت به هنگام ادغام نیاز به رسیدگی دقیق تری است
- برای مقابله با تداخل ها به کار بیشتری نیاز است، زیرا تداخل های مشابه باید بارها و بارها حل شوند تا شاخه ویژگی به روز شود، و تداخل ها باید به ترتیبی که برای ادامه بازنمود ایجاد شده اند حل شوند.