Merge Conflict چیست و چگونه اصولی حل میشود؟
Conflict وقتی دو تغییر ناسازگار روی یک ناحیه است؛ خواندن markerها، استفاده از status/diff، abort، و جلوگیری با همگامسازی زود — از git-scm و Pro Git.
Founder & product engineer

Conflict یعنی Git نتوانسته بهصورت خودکار تصمیم بگیرد کدام تغییر باید در نتیجه بماند — معمولاً چون دو Branch یک ناحیه از یک فایل را به شکل ناسازگار عوض کردهاند. این شکست نیست؛ جایگزین overwrite خام است. وحشت وقتی شروع میشود که markerها را نفهمید یا «Accept All» را بدون فکر بزنید.
مستندات GitHub About merge conflicts و Pro Git همین را میگویند: ادغام متوقف میشود، فایلهای تعارضدار علامت میخورند، و شما باید نتیجه را بسازید، Stage کنید و Commit ادغام را تمام کنید. همین الگو در rebase هم ظاهر میشود، با فرمانهای continue/abort متفاوت.

پاسخ کوتاه
Conflict وضعیت نیمهکارهٔ Merge (یا Rebase) است. فایلها با علامتهای <<<<<<< ======= >>>>>>> بخشهای رقیب را نشان میدهند. راه حل: محتوای نهایی درست را بنویسید (گاهی ترکیب هر دو طرف)، فایل را git add کنید، سپس git commit (برای merge) یا git rebase --continue. اگر اشتباه آمدید: git merge --abort یا git rebase --abort در صورت امکان.
Conflict پیام «انسان تصمیم بگیرد» است؛ پاک کردن بیفکر markerها باگ پنهان میسازد.
چرا Conflict پیش میآید؟ مسئلهٔ واقعی
- دو نفر یک تابع را همزمان بازنویسی کردهاند.
- Branch فیچر دیر با main همگام شده و همان خطوط چندبار عوض شدهاند.
- Reorder یا فرمت خودکار (لینتر) روی همان ناحیه در دو سمت.
- تغییر نام/حذف در یک سمت و ویرایش در سمت دیگر (گاهی Conflict خاص).
پیشگیری عملی: Branch کوتاهعمر، همگامسازی مکرر با پایه، و تقسیم مسئولیت فایلهای داغ. حذف کامل Conflict در تیم موازی غیرواقعی است.
تشخیص: status و marker
bash
git status # Unmerged paths # both modified: src/app.py
نمونهٔ marker کلاسیک:
text
<<<<<<< HEAD return old_behavior() ======= return new_behavior() >>>>>>> feature/x
HEAD معمولاً سمت Branch جاری است؛ پایینتر سمت Branch در حال ادغام. در ابزارهای GUI برچسب Ours/Theirs ممکن است در Merge و Rebase جابهجا حس شود — همیشه محتوا را بخوانید نه فقط برچسب.
مسیر حل اصولی
- هدف محصول را بفهمید: کدام رفتار درست است؟ گاهی هر دو تکه لازم است.
- Markerها را کامل حذف کنید؛ فایل نباید <<<<<<< باقی بگذارد.
- تست محلی یا حداقل کامپایل/لینت همان بخش.
- git add روی فایلهای حلشده.
- اتمام: git commit برای Merge (پیام پیشفرض ادغام را تکمیل کنید) یا rebase --continue.
bash
git add src/app.py git commit # تکمیل merge # یا در rebase: # git rebase --continue
جدول: ابزار و ریسک
| رویکرد | مناسب برای | ریسک |
|---|---|---|
| ویرایش دستی + فهم | منطق حساس | زمانبر |
| GUI سه ستونه | فایل بزرگ | Accept اشتباه |
| checkout --ours/--theirs | وقتی یکی کاملاً درست است | از دست رفتن سمت دیگر |
| Abort و شروع مجدد | ادغام زودرس/اشتباه | از دست رفتن حلهای نیمهکاره |
Conflict در Pull Request روی GitHub
GitHub وقتی نتواند Merge کند هشدار میدهد. میتوانید در UI برای تعارضهای ساده حل کنید یا محلی Merge/Rebase کنید و Push بیاورید. تعارضهای پیچیدهٔ منطقی را بهتر است محلی با تست حل کنید. Branch protection ممکن است تا رفع Conflict و سبز شدن CI اجازهٔ Merge ندهد.
بعد از حل: چه چیزی را بررسی کنید؟
- هیچ marker باقی نمانده (جستوجوی <<<<<<< در مخزن).
- Importها و پرانتزها بعد از ادغام شکسته نشده.
- رفتار هر دو فیچر اگر باید همزیستی کنند حفظ شده.
- پیام Commit ادغام وضعیت را توضیح میدهد اگر غیرعادی بود.
اشتباههای رایج
- Commit کردن markerها بهخاطر عجله.
- Always Ours بدون خواندن تغییرات امنیتی سمت دیگر.
- حل Conflict در rebase عمومی با force push بدون هماهنگی.
- ترس از abort؛ abort بهتر از تاریخچهٔ سمی است.
- یکیگرفتن «Conflict نیست» با «از نظر محصول درست Merge شده».
مثال کامل کوتاه
فرض کنید روی main تابع نرخ مالیات عوض شده و روی feature همان تابع برای معافیت جدید گسترش یافته. Merge marker دو نسخه را نشان میدهد. حل درست اغلب ترکیب است: رفتار معافیت + نرخ جدید — نه انتخاب کور Ours.
بعد از ویرایش:
bash
rg '<<<<<<<' -n || true git add src/tax.py git commit -m "Merge branch 'feature/tax-exempt'; resolve tax rate + exemption"
Conflict در rebase: تفاوت فرمان
در rebase بهجای یک Commit ادغام، ممکن است چند بار Conflict ببینید. پس از حل هر مرحله: git add و git rebase --continue. برای انصراف: git rebase --abort. قاطی کردن فرمانهای merge و rebase در میانهٔ عملیات وضعیت را بدتر میکند — اول status را بخوانید که کدام عملیات در جریان است.
ابزار کمکی و مرز مسئولیت
- mergetool و GUI سه ستونه برای فایل بزرگ مفیدند.
- لینتر/فرمت بعد از حل Conflict دوباره اجرا شود تا marker یا استایل نشکند.
- برای فایل تولیدشده (lockfile) گاهی انتخاب یک سمت + regenerate بهتر از ادغام دستی است.
اولویتبندی وقتی دهها فایل Conflict دارند
اول فایلهای منطق کسبوکار، بعد پیکربندی، بعد فایلهای تولیدشده. lockfile را معمولاً یک سمت بگیرید و با نصب وابستگی دوباره بسازید. اگر Conflict بهخاطر reformat عظیم است، PR فرمت را جدا کنید تا دفعهٔ بعد تکرار نشود.
ثبت دانش بعد از Conflict سخت
اگر حل Conflict بیش از سی دقیقه طول کشید، در بدنهٔ PR یا یادداشت تیم بنویسید کدام الگوی تداخل بود (مثلاً دو نفر همزمان API را عوض کردند). این بازخورد به تخصیص کار و مالکیت ماژول برمیگردد — ریشه اغلب فرآیندی است نه فقط فنی.
Conflict ساختگی با ابزار تولید کد
فرمت خودکار، codegen و AI گاهی یک فایل را در دو Branch به شکل متفاوت بازنویسی میکنند حتی وقتی منطق یکی است. راه کاهش: یک نسخهٔ فرمت را در pipeline اجباری کنید، codegen را Commit کنید یا نکنید با قرارداد ثابت، و PRهای «فقط فرمت» را از PR منطق جدا کنید. در غیر این صورت Conflictهای بیمعنی زمان Review را میبلعند.
چکلیست پایان Conflict
- جستوجوی marker در کل مخزن.
- اجرای تستهای مرتبط با فایلهای حلشده.
- نگاه به diff نهایی ادغام انگار Reviewer هستید.
- تکمیل Commit/ادامهٔ rebase با پیام واضح.
- اگر روی PR هستید، Push و اطمینان از سبز شدن مجدد CI.
سوالات متداول
آیا Conflict یعنی کد یکی غلط است؟
نه لزوماً؛ یعنی Git تصمیم بیابهام ندارد. هر دو تغییر ممکن است درست ولی ناسازگار باشند.
باینری Conflict چگونه است؟
برای فایل باینری معمولاً باید یک نسخه را انتخاب کنید یا ابزار تخصصی؛ marker متنی معنی ندارد.
چطور Conflict را کم کنیم؟
ادغام مکرر، مالکیت واضح ماژول، و اجتناب از reformat عظیم در همان PRی که منطق عوض میکند.
خلاصه
Merge Conflict توقف کنترلشده برای تصمیم انسانی است. با خواندن marker، ساخت نتیجهٔ درست، Stage و تکمیل Merge/Rebase حل میشود. پیشگیری با Branch کوتاه و همگامسازی است؛ حذف کامل در کار موازی ممکن نیست.
برای مکانیک Merge به ۲۰۶ و برای خطیسازی با Rebase به ۲۱۰ برگردید.
منابع و مراجع
- Pro Git — Basic Merging (conflicts) — https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
- git-merge documentation — https://git-scm.com/docs/git-merge
- GitHub Docs — About merge conflicts — https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/about-merge-conflicts
- GitHub Docs — Resolving a merge conflict on GitHub — https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-on-github
- GitHub Docs — Resolving a merge conflict using the command line — https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line
Author
Soheil Ebrahimpour is the founder of FutureForge. He works on product design, architecture, and getting custom software into production.
Related notes
If you are unsure about architecture or the build path, we can talk about the project.
Describe the problem and the constraints. If there is a fit, we will schedule a conversation.




