git merge
ضمّ تاريخين تطويريين أو أكثر معًا
يدمج الأمر 'git merge' في الفرع الحالي تغييرات الـ commits المسمّاة (منذ أن تباعد تاريخها عن الفرع الحالي). ينفّذ Git دمج «fast-forward» حين يمكن ذلك (حين يكون الفرع الحالي سلفًا للفرع المدموج)، أو ينشئ «commit دمج» حين يتباعد التاريخان. وإن وُجدت تعارضات بين الفرعين، يتوقف Git ويطلب منك حلّها قبل إكمال الدمج.
الصيغة
git merge [--no-ff | --ff-only] [--squash] [--no-commit] [-m <msg>] [--allow-unrelated-histories] [<commit>...]
git merge (--continue | --abort | --quit)الخيارات
اختيار الخيار المناسب
استراتيجيات الدمج
كيف تتحكم في نوع الدمج الذي ينفّذه Git
| الأمر | ينشئ commit دمج | يحافظ على التاريخ | الأنسب لـ |
|---|---|---|---|
git merge (default) | إن تباعدا | نعم | الدمج المعتاد للميزات |
git merge --no-ff | دائمًا | نعم | توثيق دمج الميزات |
git merge --ff-only | أبدًا | خطي فقط | فرض تاريخ نظيف |
git merge --squash | لا (commit عادي) | لا (مسطّح) | فرع main نظيف |
التعامل مع التعارضات
ماذا تفعل حين يحتوي الدمج على تعارضات
| الأمر | الإجراء | يُبقي العمل | متى تستخدمه |
|---|---|---|---|
(resolve manually) | عدّل الملفات، git add | نعم | تحتاج أجزاء من الطرفين |
--continue | إكمال الدمج | نعم | بعد حل التعارضات |
--abort | إلغاء الدمج | حالة ما قبل الدمج | لست مستعدًا للحل الآن |
checkout --ours/--theirs | اختر طرفًا | نسخة واحدة | أحد الطرفين صحيح بوضوح |
merge مقابل rebase
طريقتان لدمج التغييرات - بمزايا وعيوب مختلفة
| الأمر | التاريخ | حل التعارضات | الأنسب لـ |
|---|---|---|---|
git merge | يحافظ على كل الـ commits | مرة واحدة | الفروع المشتركة، طلبات الدمج |
git rebase | يعيد الكتابة خطيًا | لكل commit | التنظيف المحلي، الفروع الخاصة |
git merge --squash | commit واحد | مرة واحدة | ميزة بتاريخ فوضوي |
التحكم في الـ commit
خيارات لتخصيص commit الدمج
| الأمر | يحفظ تلقائيًا | حالة الاستخدام |
|---|---|---|
git merge feature | نعم (إن لم توجد تعارضات) | دمج عادي |
git merge --no-commit | لا (مجهَّز) | المراجعة قبل الـ commit |
git merge -m "msg" | نعم (يُتجاهل في fast-forward) | commits دمج وصفية |
git merge --squash | لا (يجب الحفظ) | جمع كل الـ commits في واحد |
أمثلة على سير العمل
git checkout mainانتقل إلى الفرع main
git pull origin mainاجلب أحدث التغييرات من المستودع البعيد
git merge --no-ff feature-branchادمج الميزة بـ commit دمج من أجل التاريخ
git push origin mainادفع التغييرات المدموجة إلى المستودع البعيد
git branch -d feature-branchاحذف فرع الميزة المدموج
git merge featureحاول الدمج (تظهر تعارضات)
git statusاعرف الملفات التي فيها تعارضات
(edit conflicted files)ابحث عن علامات <<<<<<< وحلّها يدويًا
git add <resolved-files>جهّز الملفات المحلولة
git merge --continueأكمل الدمج بـ commit
git checkout mainانتقل إلى الفرع main
git merge --squash feature-branchاجمع كل الـ commits في تغييرات مجهّزة
git commit -m "Add feature X"أنشئ commit واحدًا نظيفًا بكل التغييرات
git branch -D feature-branchاحذف فرع الميزة بالإجبار
git merge featureابدأ الدمج (تظهر مشكلات)
git statusاعرض حالة التعارض
git merge --abortألغِ واستعد حالة ما قبل الدمج
git statusتأكد أنك عدت إلى حالة نظيفة
حل المشكلات
CONFLICT (content): Merge conflict in file.js
السبب: عدّل الفرعان الأسطر نفسها في الملف
افتح الملف، وابحث عن علامات <<<<<<<، وحلّ التعارض، ثم git add وgit merge --continue
fatal: refusing to merge unrelated histories
السبب: ليس للفرعين سلف مشترك (مستودعات منفصلة)
استخدم git merge --allow-unrelated-histories إن كنت تريد عمدًا جمع مشاريع منفصلة
Already up to date
السبب: الفرع الذي تدمجه مضمَّن أصلًا في فرعك الحالي
لا شيء لفعله - فرعك يحتوي أصلًا كل commits الهدف
error: Your local changes to the following files would be overwritten by merge
السبب: لديك تغييرات غير محفوظة تتعارض مع الدمج
احفظ تغييراتك في commit، أو خبّئها (git stash)، أو تخلّص منها قبل الدمج
تمّ الدمج لكنني أردت المراجعة أولًا
السبب: حفظ Git الدمج تلقائيًا
في المرة القادمة استخدم --no-ff --no-commit. لإعادته: git reset --merge ORIG_HEAD، ثم ادمج مجددًا مع --no-commit
نصائح وأخطاء شائعة
أفضل الممارسات
- ✓اسحب دائمًا أحدث التغييرات قبل الدمج لتقليل التعارضات
- ✓استخدم --no-ff لفروع الميزات للحفاظ على سياق الدمج في التاريخ
- ✓اكتب رسائل دمج وصفية تشرح ما الذي دُمج
- ✓احذف فروع الميزات بعد الدمج ليبقى المستودع نظيفًا
- ✓اختبر شيفرتك بعد الدمج وقبل الدفع للتأكد أن شيئًا لم يتعطل
- ✓استخدم git merge --abort إن لم تكن مستعدًا لحل التعارضات - لا تترك الدمج في حالة معطوبة
- ✓في الفروع طويلة الأمد، ادمج main في فرع ميزتك دوريًا لتقليل تعارضات الدمج النهائي
أخطاء متكررة
- ✗الدمج دون سحب أحدث التغييرات من المستودع البعيد أولًا. نفّذ دائمًا 'git pull' قبل الدمج لتجنّب التعارضات.
- ✗تجهيز ملفات ما زالت فيها علامات التعارض. يمنع Git الـ commits ما دامت هناك مسارات غير مدموجة، لكن بمجرد أن تنفّذ 'git add' على ملف يحفظ علامات <<<<<<< كما هي.
- ✗استخدام دمج fast-forward لفروع الميزات يُضيّع تاريخ الفرع. استخدم '--no-ff' للحفاظ على السياق.
- ✗تشغيل 'git merge --abort' بعد حل التعارضات يدويًا يُضيّع كل عمل الحل.
- ✗الدمج في الفرع الخطأ. تحقّق دائمًا بـ 'git branch' أنك على الفرع الهدف الصحيح قبل الدمج.
الأسئلة الشائعة
يحافظ merge على التاريخ وينشئ commit دمج. ويعيد rebase كتابة التاريخ ليصبح خطيًا. استخدم merge للفروع المشتركة، وrebase للتنظيف المحلي.
استخدم --no-ff عند دمج فروع الميزات في main. ينشئ commit دمج يوثّق متى دُمجت الميزة، حتى لو كان fast-forward ممكنًا.
إن لم يُدفع: git reset --hard ORIG_HEAD (يعمل مع fast-forward أيضًا؛ ويتخلّص من التغييرات غير المحفوظة). إن دُفع: git revert -m 1 <merge-commit> لإنشاء commit جديد يلغي الدمج.
يحدث fast-forward حين لا يحتوي فرعك على commits جديدة منذ نقطة التفرّع. فيحرّك Git المؤشر إلى الأمام فقط بدل إنشاء commit دمج.
افتح الملفات المتعارضة، وابحث عن علامات <<<<<<<، وعدّلها لتُبقي الشيفرة التي تريدها، وأزل العلامات، ثم نفّذ git add على الملفات وgit merge --continue.
الدمج العادي يحافظ على كل تاريخ الـ commits. ودمج squash يجمع كل شيء في commit واحد. استخدم squash حين يحتوي فرع الميزة على commits مؤقتة فوضوية لا تريدها في main.