git cherry-pick

الفروع والدمج

تطبيق تغييرات commits محددة على الفرع الحالي


يطبّق الأمر 'git cherry-pick' التغييرات التي أدخلها commit أو أكثر موجود على الفرع الحالي، منشئًا commit جديدًا لكل منها. بخلاف merge وrebase اللذين يعملان على فروع كاملة، يتيح لك cherry-pick نسخ commits محددة انتقائيًا. هذا لا يُقدّر بثمن لنقل الإصلاحات العاجلة إلى فروع الإصدار، واستعادة commits ضائعة، وجلب ميزات محددة من فرع إلى آخر دون دمج كل شيء. يحصل كل commit منسوخ على SHA جديد - إنه نسخة، لا نقل. cherry-pick دقيق كالجراحة، ويمنحك تحكمًا دقيقًا فيما يصل إلى فرعك من تغييرات.

الصيغة

git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff] [-S[<keyid>]] <commit>...
git cherry-pick (--continue | --skip | --abort | --quit)
[ ] اختياري| أو<arg> قيمة تُستبدل... قابل للتكرار--flag خيار

الخيارات

انقر على أي خيار لتوسيعه

مبتدئ (2)

طبّق التغييرات على مجلد العمل والفهرس دون إنشاء commit. مثالي لجمع عدة عمليات cherry-pick في commit واحد.

عند الحاجةجمع عدة عمليات cherry-pick في commit واحد

مثال

git cherry-pick -n abc1234

افتح المحرر لتعديل رسالة الـ commit قبل حفظه. استخدمه لتوضيح سبب نسخ الـ commit.

عند الحاجةيضيف سياقًا إلى رسالة الـ commit المنسوخ

مثال

git cherry-pick -e abc1234

متوسط (5)

استأنف cherry-pick بعد حل التعارضات. يجب تجهيز الملفات المحلولة بـ 'git add' أولًا.

موصى بهيستأنف بعد أن تحل التعارضات وتجهّزها

مثال

git cherry-pick --continue

ألغِ عملية cherry-pick وأعد الفرع إلى حالته قبلها. استخدمه عندما تكون التعارضات معقّدة جدًا أو اخترت الـ commit الخطأ.

موصى بهيلغي بأمان ويعيد الحالة التي سبقت الـ cherry-pick

مثال

git cherry-pick --abort

تخطَّ الـ commit الحالي وتابع مع بقية الـ commits في التسلسل. لا تُطبَّق تغييرات الـ commit المتخطّى.

عند الحاجةيتخطّى commit لم تعد تحتاج تغييراته

مثال

git cherry-pick --skip

ألحق '(cherry picked from commit ...)' برسالة الـ commit. يساعد على تتبّع أصل الـ commits المنسوخة.

موصى بهيسجّل الـ commit المصدر — ضروري لنقل الإصلاحات

مثال

git cherry-pick -x abc1234

أضف سطر 'Signed-off-by' باسمك وبريدك. تطلبه بعض المشاريع لأسباب قانونية أو تدقيقية.

عند الحاجةفقط إذا كان المشروع يشترط أسطر Signed-off-by

مثال

git cherry-pick -s abc1234

متقدم (2)

أبقِ الـ commits التي كانت فارغة من البداية (الشجرة نفسها لأبيها). أما الـ commits التي تصبح فارغة لأن تغييراتها موجودة أصلًا فما زالت توقف العملية؛ استخدم ‎--empty=keep لها.

عند الحاجةفقط للـ commits التي كانت فارغة من الأصل

مثال

git cherry-pick --allow-empty abc1234

مطلوب عند نسخ commits الدمج. يحدد الأب (1 أو 2) الذي يمثّل الخط الرئيسي. عادةً -m 1 للحصول على تغييرات الفرع المدموج.

عند الحاجةإلزامي مع commits الدمج؛ وعادةً -m 1

مثال

git cherry-pick -m 1 abc1234

خبير (2)

استخدم استراتيجية الدمج المحددة عند تطبيق التغييرات. الافتراضي 'ort' (أو 'recursive' في Git الأقدم). لا صيغة مختصرة له: -s تعني هنا ‎--signoff.

غير موصى بهاستراتيجية ort الافتراضية هي الصحيحة في الغالب

مثال

git cherry-pick --strategy=ort abc1234

مرّر خيارات إلى استراتيجية الدمج. الشائع: 'theirs' (تفضيل التغييرات المختارة)، و'ours' (تفضيل الحالي)، و'patience' (diffs أفضل).

غير موصى بهيتخلّص -Xours / -Xtheirs بصمت من أحد طرفي الأجزاء المتعارضة

مثال

git cherry-pick -Xtheirs abc1234

اختيار الخيار المناسب

مقارنة git cherry-pick بالأوامر القريبة منه

متى تستخدم cherry-pick بدل merge أو rebase أو revert

الأمرالجانبCherry-pickأمر آخر
Scopecommits محددة فقطMerge: الفرع كله / Rebase: الفرع كله
Creates new commitsنعم - SHA جديد، المحتوى نفسهMerge: commit دمج / Rebase: يعيد كتابة الكل
Original staysنعم - الأصل لا يُمسMerge: نعم / Rebase: يتيم
Use caseالنقل العكسي، النقل الانتقائيدمج فروع كاملة
History effectينشئ تغييرات مكررةيحافظ عليه أو يجعله خطيًا
Conflictsلكل commit أثناء الـ pickعند نقطة الدمج أو لكل commit في rebase

أمثلة على سير العمل

1
git checkout release-1.0

انتقل إلى فرع الإصدار

2
git log main --oneline

اعثر على hash الـ commit الخاص بالإصلاح

3
git cherry-pick -x abc123

طبّق الإصلاح مع مرجع المصدر

4
git push origin release-1.0

ادفع الإصلاح المنقول

1
git checkout main

انتقل إلى الفرع main

2
git log feature --oneline

راجع الـ commits على فرع الميزة

3
git cherry-pick abc123 def456

اختر الـ commits الجاهزة فقط

4
git push origin main

ادفع الـ commits المختارة

1
git reflog

اعثر على hash الـ commit في الـ reflog

2
git checkout main

انتقل إلى الفرع الهدف

3
git cherry-pick abc123

طبّق الـ commit اليتيم

1
git checkout target-branch

انتقل إلى فرع الوجهة

2
git cherry-pick A^..C

طبّق الـ commits من A إلى C (ضمنًا)

3
git log --oneline

تحقّق من تطبيق الـ commits

حل المشكلات

"commit is a merge but no -m option was given"

السبب: تحاول نسخ commit دمج دون تحديد الأب

استخدم -m 1 أو -m 2 لتحديد أب الخط الرئيسي

git cherry-pick -m 1 <merge-commit>

تعارضات أثناء cherry-pick

السبب: التغييرات تتعارض مع فرعك الحالي

حلّ التعارضات في الملفات، ونفّذ git add عليها، ثم git cherry-pick --continue. أو ألغِ بـ ‎--abort

git add <resolved-files> && git cherry-pick --continue

"The previous cherry-pick is now empty"

السبب: تغييرات الـ commit موجودة أصلًا في فرعك

شغّل 'git commit --allow-empty' لتسجيله رغم ذلك، أو 'git cherry-pick --skip' لتخطيه

git cherry-pick --skip

أنشأ cherry-pick commits مكررة

السبب: التغييرات نفسها موجودة الآن كـ commits مختلفة على فروع مختلفة

هذا هو السلوك المتوقع. استخدم الخيار -x لتوثيق العلاقة

git cherry-pick -x <commit>

نُسخ الـ commit الخطأ

السبب: اخترت SHA الـ commit الخطأ

إن لم يُدفع: git reset --hard HEAD~1. إن دُفع: نفّذ git revert على الـ commit المنسوخ

git reset --hard HEAD~1

يبدو أن cherry-pick بلا أثر

السبب: قد يكون الـ commit فارغًا أو تغييراته مطبّقة أصلًا

راجع git diff HEAD~1 لرؤية التغييرات الفعلية

git diff HEAD~1

نصائح وأخطاء شائعة

أفضل الممارسات

  • ✓استخدم -x في النقل العكسي (backport) لإضافة المرجع '(cherry picked from commit ...)' إلى رسالة الـ commit
  • ✓نفّذ cherry-pick بالترتيب الزمني - يجب تطبيق الـ commits المعتمدة على غيرها من الأقدم إلى الأحدث لتجنّب التعارضات
  • ✓فضّل merge للفروع المشتركة - cherry-pick ينشئ commits مكررة بينما يحافظ merge على التاريخ
  • ✓اختبر بعد الـ cherry-pick - قد يعمل الـ commit في سياقه الأصلي ويفشل في الجديد
  • ✓وثّق عمليات cherry-pick في رسائل الـ commits بالخيار -e لتوضيح سبب نسخ الـ commit
  • ✓استخدم ‎--no-commit لجمع عمليات pick المترابطة في commit واحد أنظف
  • ✓فكّر في استخدام git cherry بدل log لإيجاد الـ commits التي لم تُطبَّق بعد
  • ✓عند النقل العكسي، ضمّن دائمًا hash الـ commit الأصلي في الرسالة لإمكانية التتبّع

أخطاء متكررة

  • ✗نسيان -m مع commits الدمج. نسخ commit دمج بـ cherry-pick دون '-m 1' أو '-m 2' يفشل - يجب أن تحدد الأب الذي يُحسب الـ diff مقارنةً به.
  • ✗عدم تجهيز الملفات المحلولة قبل ‎--continue. يجب تشغيل 'git add' على الملفات المحلولة قبل 'git cherry-pick --continue'.
  • ✗توقّع الـ hash نفسه للـ commit. ينشئ cherry-pick commits جديدة بـ SHA جديد - إنه ينسخ التغييرات ولا ينقل الـ commits.
  • ✗نسخ commits مطبّقة أصلًا. يسبب هذا تعارضات أو commits فارغة - تحقّق أولًا بـ 'git log'.
  • ✗اختيار الـ commits بترتيب خاطئ. يجب اختيار الـ commits المعتمدة على غيرها من الأقدم إلى الأحدث، وإلا ظهرت تعارضات.
  • ✗استخدام cherry-pick على الفروع العامة ينشئ commits مكررة حين يملك آخرون الأصل - فضّل merge للفروع المشتركة.

الأسئلة الشائعة

A:

لا. ينشئ cherry-pick commit جديدًا بالتغييرات نفسها لكن بـ SHA مختلف. ويبقى الـ commit الأصلي حيث كان.

A:

يعتمد hash الـ commit في Git على المحتوى والأب والمؤلف والتاريخ والرسالة. يُبقي cherry-pick المؤلف وتاريخ التأليف، لكن الأب وتاريخ الـ committer يختلفان، فيتغيّر الـ hash حتى لو كانت التغييرات متطابقة.

A:

نعم! اذكرها: git cherry-pick A B C، أو استخدم النطاقات: git cherry-pick A^..C (يشمل A وC).

A:

استخدم الخيار -m: ‏git cherry-pick -m 1 <merge-commit>. يحدد الرقم الأب الذي يمثّل الخط الرئيسي (عادةً 1).

A:

A..B يستثني A (الـ commits بعد A حتى B). A^..B يشمل A (الـ commits من A إلى B ضمنًا).

A:

إن لم يُدفع: git reset --hard HEAD~1. إن دُفع: git revert <commit> لإنشاء commit يتراجع عنه.

A:

cherry-pick لـ commits محددة. rebase لنقل فروع كاملة. إن احتجت معظم commits الفرع، فـ rebase أنظف.