Merge — چیست، انواع ادغام و مکانیزم کار

نویسنده: IT Sectr منتشر شده: 2026-05-10 زمان مطالعه: 10 دقیقه

Merge — عملیاتی در Git است که تغییرات را از یک شاخه به شاخه دیگر ادغام می‌کند و یک commit ادغام (merge commit) ایجاد می‌کند. Git از چندین استراتژی پشتیبانی می‌کند: fast-forward (تاریخ خطی)، three-way merge (با ایجاد merge commit) و squash merge (فشرده‌سازی همه commitها در یک commit). طبق داده‌های git-scm.com, 2025، merge همچنان پرکاربردترین مکانیزم یکپارچه‌سازی کد در توسعه تیمی با Git است.

نکات اصلی

  • Merge — عملیات ادغام شاخه‌ها در Git با یا بدون commit ادغام
  • Fast-forward merge — ادغام خطی بدون commit اضافی، وقتی اختلافی وجود ندارد
  • Three-way merge — هنگام اختلاف شاخه‌ها merge commit ایجاد می‌کند
  • Squash merge — همه commitهای شاخه را قبل از ادغام در یک commit فشرده می‌کند
  • تعارضات هنگام تغییر خطوط یکسان در هر دو شاخه ایجاد می‌شوند

Merge چیست؟

Merge (ادغام) — یک عملیات اساسی در Git است که تغییرات را از یک شاخه (source) به شاخه دیگر (target) ادغام می‌کند. در نتیجه ادغام، شاخه هدف تمام commitهایی را که در شاخه مبدأ وجود داشته و در آن نبوده است دریافت می‌کند. بسته به شرایط، Git می‌تواند merge را به سه روش مختلف انجام دهد.

ارزش اصلی merge — حفظ تاریخ است: merge commit واقعیت ادغام شاخه‌ها را ثبت می‌کند، اطلاعات مربوط به زمان و اینکه کدام شاخه‌ها ادغام شده‌اند را حفظ می‌کند. این کار حسابرسی تغییرات، جستجوی رگرسیون‌ها و درک گاهشماری توسعه را تسهیل می‌کند. در پروژه‌های بزرگ، merge commit روش استاندارد یکپارچه‌سازی کد است.

طبق داده‌های GitLab Flow، merge commitها در ۷۳٪ تیم‌هایی که با Git کار می‌کنند استفاده می‌شود. رویکردهای جایگزین (rebase, squash) توسط تیم‌هایی که به تاریخ خطی تمایل دارند ترجیح داده می‌شود. انتخاب استراتژی به اندازه تیم، فراوانی انتشار و توافقات پذیرفته‌شده در پروژه بستگی دارد.

چه زمانی Merge لازم است

Merge زمانی لازم است که توسعه‌دهنده کار روی یک ویژگی را تمام کرده و می‌خواهد آن را در develop یا main ادغام کند. سناریوی معمول: توسعه‌دهنده یک شاخه ویژگی از develop ایجاد کرد، چند روز روی آن کار کرد و در این مدت commitهای جدیدی از سایر شرکت‌کنندگان در develop ظاهر شد. قبل از ادغام باید تغییرات را ترکیب کرد — و برای این کار از merge استفاده می‌شود.

بدون merge امکان کار گروهی روی یک کد در Git وجود ندارد. هر بار که دو توسعه‌دهنده به طور همزمان تغییراتی را در یک پایگاه کد وارد می‌کنند، شاخه‌های آنها از هم جدا می‌شود. Merge — تنها راه برای بازگرداندن این تغییرات بدون از دست دادن داده‌ها است.

انواع ادغام در Git

Git از سه نوع merge پشتیبانی می‌کند که هر کدام برای سناریوی خاص خود طراحی شده‌اند. انتخاب نوع ادغام بر تاریخ commitها، راحتی بازگشت و خوانایی لاگ تأثیر می‌گذارد.

Fast-forward merge

Fast-forward زمانی رخ می‌دهد که شاخه هدف از زمان ایجاد شاخه مبدأ commit جدیدی نداشته باشد. در این حالت Git به سادگی نشانگر شاخه هدف را به جلو، به آخرین commit شاخه مبدأ منتقل می‌کند. تاریخ بدون merge commit خطی باقی می‌ماند.

bash
# Fast-forward merge: develop از زمان ایجاد feature تغییر نکرده است
git checkout develop
git merge feature/new-login

# نتیجه: نشانگر develop به انتهای feature منتقل شد
# هیچ merge commitای ایجاد نشد

Fast-forward برای شاخه‌های کوتاه‌عمر مناسب است، جایی که توسعه‌دهنده به تنهایی کار می‌کرد. اما این رویکرد یک اشکال دارد: اطلاعات مربوط به وجود شاخه از دست می‌رود — همه commitها به نظر می‌رسند که مستقیماً در develop انجام شده‌اند.

Three-way merge

Three-way merge زمانی اجرا می‌شود که هر دو شاخه بعد از نقطه واگرایی commitهای جدیدی داشته باشند. Git یک commit ادغام جداگانه با دو والد ایجاد می‌کند که واقعیت ادغام شاخه‌ها را ثبت می‌کند. این رویکرد برای شاخه‌های ویژگی در توسعه تیمی توصیه می‌شود.

bash
# Three-way merge اجباری با پرچم --no-ff
git checkout develop
git merge --no-ff feature/new-login

# merge commit با پیام پیش‌فرض ایجاد شد
# می‌توانید پیام خود را از طریق -m تنظیم کنید
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"

پرچم --no-ff ایجاد merge commit را تضمین می‌کند، حتی اگر fast-forward ممکن باشد. این بهترین روش برای حفظ اطلاعات مربوط به انشعاب در پروژه است.

Squash merge

Squash merge همه commitهای شاخه مبدأ را در یک commit فشرده کرده و به شاخه هدف اعمال می‌کند. تاریخچه ویژگی از بین می‌رود — یک commit با تمام تغییرات وارد شاخه می‌شود. این زمانی مفید است که commitهای جزئی در شاخه ویژگی برای تاریخ کلی ارزشی ندارند.

bash
# Squash merge: همه commitهای feature در یک commit فشرده شدند
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"

Squash برای پیش‌نویس‌ها، شاخه‌های آزمایشی و موقعیت‌هایی که حفظ تمیزی تاریخ مهم است مناسب است. نکته منفی — ارتباط با commitهای اصلی از دست می‌رود که بازگرداندن تغییرات جداگانه را دشوار می‌کند.

استراتژی‌های Ours و Theirs

Ours و Theirs — دو استراتژی ویژه merge در Git. Ours تغییرات شاخه مبدأ را کاملاً نادیده می‌گیرد و فقط آنچه را که در شاخه هدف است حفظ می‌کند. Theirs برعکس، در هر تعارضی نسخه شاخه مبدأ را می‌پذیرد. این استراتژی‌ها هنگام ادغام حجم زیادی از کد مفید هستند، زمانی که از قبل مشخص است کدام نسخه باید پیروز شود.

Merge چگونه کار می‌کند

مکانیزم merge در Git بر اساس مقایسه سه نقطه است: جد مشترک (merge base)، وضعیت شاخه مبدأ و وضعیت شاخه هدف. Git merge base — آخرین commit مشترک برای هر دو شاخه — را پیدا می‌کند و محاسبه می‌کند که چه تغییراتی در هر شاخه پس از واگرایی رخ داده است.

  • مرحله ۱ — Git merge base را تعیین می‌کند: آخرین commit که در هر دو شاخه وجود دارد
  • مرحله ۲ — Git دو diff می‌سازد: از merge base تا source و از merge base تا target
  • مرحله ۳ — Git سعی می‌کند هر دو مجموعه تغییرات را به merge base اعمال کند
  • مرحله ۴ — اگر تغییرات تداخل نداشته باشند — merge به طور خودکار پایان می‌یابد
  • مرحله ۵ — اگر تعارض وجود داشته باشد — Git متوقف می‌شود و درخواست حل می‌کند

Git از الگوریتم سه‌جانبه ادغام استفاده می‌کند که نه تنها دو نسخه مقایسه‌شده فایل، بلکه جد مشترک آنها را نیز در نظر می‌گیرد. به لطف این، Git می‌تواند به طور خودکار موقعیت‌هایی را حل کند که تغییرات در یک شاخه به بخش‌های تغییر یافته شاخه دیگر برخورد نمی‌کند — حتی اگر هر دو فایل تغییر کرده باشند.

الگوریتم کار merge با مثال

سناریو را در نظر بگیرید: دو توسعه‌دهنده روی فایل‌های مختلف در یک شاخه ویژگی کار می‌کنند. اولی LoginActivity.kt را تغییر داد، دومی ProfileFragment.kt را. وقتی تغییرات خود را ادغام می‌کنند، Git می‌بیند که تغییرات به فایل‌های مختلف مربوط می‌شوند و merge را به طور خودکار بدون دخالت انسان انجام می‌دهد.

اگر هر دو توسعه‌دهنده LoginActivity.kt را تغییر داده‌اند، اما در متدهای مختلف — Git نیز به طور خودکار از عهده برمی‌آید و تغییرات را خط به خط ترکیب می‌کند. تعارض فقط زمانی ایجاد می‌شود که هر دو خطوط یکسان را تغییر داده باشند یا یکی کدی را حذف کرده باشد که دیگری تغییر داده است.

حل تعارضات در Merge

تعارض merge زمانی ایجاد می‌شود که Git نمی‌تواند تغییرات را به طور خودکار ترکیب کند، زیرا هر دو شاخه خطوط یکسان را به طور متفاوت تغییر داده‌اند. در این حالت Git بخش‌های دارای تعارض را در فایل‌ها علامت‌گذاری می‌کند و منتظر حل دستی توسط توسعه‌دهنده می‌ماند.

بخش‌های دارای تعارض با نشانگرهای خاصی علامت‌گذاری می‌شوند: <<<<<<< HEAD کد شاخه هدف را نشان می‌دهد، ======= — جداکننده، >>>>>>> source-branch — کد شاخه مبدأ. توسعه‌دهنده باید به صورت دستی انتخاب کند کدام گزینه را نگه دارد یا آنها را ترکیب کند.

bash
# ۱. اجرای merge و مشاهده تعارض
git merge feature/new-login
# خروجی: CONFLICT (content): Merge conflict in LoginActivity.kt

# ۲. مشاهده لیست فایل‌های دارای تعارض
git status
# both modified: src/ui/login/LoginActivity.kt

# ۳. حل تعارض: ویرایش فایل، حذف نشانگرها
# ۴. اضافه کردن فایل حل‌شده و اتمام merge
git add src/ui/login/LoginActivity.kt
git merge --continue
# یا: git commit (بدون --continue)

برای حل تعارضات ابزارهایی وجود دارند: git mergetool یک ادغام‌کننده بصری باز می‌کند (Meld, Beyond Compare, VS Code). بسیاری از توسعه‌دهندگان ترجیح می‌دهند تعارضات را در IDE حل کنند — IntelliJ IDEA و Android Studio ابزار داخلی با مقایسه سه‌پنل‌ای ارائه می‌دهند که این فرآیند را به طور قابل توجهی ساده می‌کند.

نکاتی برای حل تعارضات: همیشه بفهمید هر طرف تعارض چه کاری انجام می‌دهد، کد دیگران را بدون درک منطق آن حذف نکنید و اگر تعارض خیلی پیچیده است — نویسنده هر دو شاخه را برای حل مشترک مشارکت دهید.

Merge در مقابل Rebase: چه زمانی کدام را انتخاب کنیم

انتخاب بین Merge و Rebase — یکی از رایج‌ترین تصمیمات معماری در Git است. هر دو رویکرد تغییرات را ترکیب می‌کنند، اما به روش‌های مختلف: merge تاریخ انشعاب را حفظ می‌کند، rebase تاریخ را بازنویسی می‌کند و آن را خطی می‌کند.

  • Merge — زمینه را حفظ می‌کند: مشخص است چه زمانی و از کدام شاخه ادغام انجام شده است. بهتر برای شاخه‌های عمومی (develop, main) و کار تیمی
  • Rebase — یک تاریخ خطی تمیز بدون merge commitهای اضافی ایجاد می‌کند. بهتر برای شاخه‌های ویژگی شخصی قبل از ارسال برای بازبینی
  • قانون: هرگز شاخه‌های عمومی را که سایر توسعه‌دهندگان استفاده می‌کنند rebase نکنید

بسیاری از تیم‌ها از رویکرد ترکیبی استفاده می‌کنند: rebase برای به‌روزرسانی شاخه ویژگی به وضعیت فعلی develop (git rebase develop)، سپس merge با پرچم --no-ff برای ثبت ادغام. این کار تاریخ تمیزی درون ویژگی و نقاط ادغام اطلاعاتی در سطح develop فراهم می‌کند.

سوالات متداول

تفاوت بین merge و merge --no-ff چیست؟

بدون --no-ff Git در صورت امکان fast-forward merge را انجام می‌دهد — به سادگی نشانگر شاخه را جابجا می‌کند. با --no-ff Git همیشه یک merge commit ایجاد می‌کند و اطلاعات مربوط به انشعاب را حفظ می‌کند. برای شاخه‌های ویژگی در توسعه تیمی توصیه می‌شود.

اگر تعارض merge بسیار بزرگ باشد چه باید کرد؟

از git mergetool یا ابزار داخلی IDE استفاده کنید. اگر تعارض ده‌ها فایل را تحت تأثیر قرار می‌دهد — احتمالاً شاخه‌ها بیش از حد از هم فاصله گرفته‌اند. در این صورت بهتر است با تیم در مورد برنامه ادغام بحث کنید، احتمالاً آن را به چند مرحله تقسیم کنید.

آیا می‌توان merge را لغو کرد؟

بله: git merge --abort merge را لغو می‌کند، اگر هنوز کامل نشده باشد (تعارض). اگر merge قبلاً کامل شده است — برای بازگشت ایمن از git reset --hard HEAD~1 یا git revert -m 1 <merge-commit> استفاده کنید.

آیا برای هر ویژگی باید merge commit ایجاد کرد؟

برای کار تیمی توصیه می‌شود. Merge commit واقعیت ادغام را ثبت می‌کند، شامل ارجاع به هر دو شاخه است و درک تاریخ را ساده می‌کند. برای شاخه‌های شخصی یا آزمایشی، squash merge یا fast-forward قابل قبول است.

merge با فایل‌های باینری چگونه کار می‌کند؟

Git نمی‌تواند فایل‌های باینری را به طور خودکار ادغام کند — یکی از نسخه‌ها را به طور کامل انتخاب می‌کند. برای فایل‌های باینری (تصاویر، .aab، .apk) توصیه می‌شود تغییرات همزمان را به حداقل برسانید و برای فایل‌های بزرگ از Git LFS استفاده کنید.

خلاصه

  • Merge — عملیات پایه Git برای ترکیب تغییرات از یک شاخه به شاخه دیگر
  • Fast-forward — ادغام خطی بدون merge commit، زمانی که اختلافی وجود ندارد
  • Three-way merge — merge commit با دو والد ایجاد می‌کند، زمینه را حفظ می‌کند
  • Squash merge — همه commitهای شاخه را در یک commit فشرده می‌کند، تاریخ ویژگی را از دست می‌دهد
  • تعارضات هنگام تغییر خطوط یکسان ایجاد می‌شوند و به صورت دستی حل می‌شوند
  • Merge با Rebase متفاوت است: اولی انشعاب را حفظ می‌کند، دومی تاریخ را خطی می‌کند
  • برای شاخه‌های عمومی merge با --no-ff توصیه می‌شود، برای شخصی — rebase یا squash

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید