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)الخيارات
اختيار الخيار المناسب
مقارنة git cherry-pick بالأوامر القريبة منه
متى تستخدم cherry-pick بدل merge أو rebase أو revert
| الأمر | الجانب | Cherry-pick | أمر آخر |
|---|---|---|---|
Scope | commits محددة فقط | Merge: الفرع كله / Rebase: الفرع كله | |
Creates new commits | نعم - SHA جديد، المحتوى نفسه | Merge: commit دمج / Rebase: يعيد كتابة الكل | |
Original stays | نعم - الأصل لا يُمس | Merge: نعم / Rebase: يتيم | |
Use case | النقل العكسي، النقل الانتقائي | دمج فروع كاملة | |
History effect | ينشئ تغييرات مكررة | يحافظ عليه أو يجعله خطيًا | |
Conflicts | لكل commit أثناء الـ pick | عند نقطة الدمج أو لكل commit في rebase |
أمثلة على سير العمل
git checkout release-1.0انتقل إلى فرع الإصدار
git log main --onelineاعثر على hash الـ commit الخاص بالإصلاح
git cherry-pick -x abc123طبّق الإصلاح مع مرجع المصدر
git push origin release-1.0ادفع الإصلاح المنقول
git checkout mainانتقل إلى الفرع main
git log feature --onelineراجع الـ commits على فرع الميزة
git cherry-pick abc123 def456اختر الـ commits الجاهزة فقط
git push origin mainادفع الـ commits المختارة
git reflogاعثر على hash الـ commit في الـ reflog
git checkout mainانتقل إلى الفرع الهدف
git cherry-pick abc123طبّق الـ commit اليتيم
git checkout target-branchانتقل إلى فرع الوجهة
git cherry-pick A^..Cطبّق الـ commits من A إلى C (ضمنًا)
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 للفروع المشتركة.
الأسئلة الشائعة
لا. ينشئ cherry-pick commit جديدًا بالتغييرات نفسها لكن بـ SHA مختلف. ويبقى الـ commit الأصلي حيث كان.
يعتمد hash الـ commit في Git على المحتوى والأب والمؤلف والتاريخ والرسالة. يُبقي cherry-pick المؤلف وتاريخ التأليف، لكن الأب وتاريخ الـ committer يختلفان، فيتغيّر الـ hash حتى لو كانت التغييرات متطابقة.
نعم! اذكرها: git cherry-pick A B C، أو استخدم النطاقات: git cherry-pick A^..C (يشمل A وC).
استخدم الخيار -m: git cherry-pick -m 1 <merge-commit>. يحدد الرقم الأب الذي يمثّل الخط الرئيسي (عادةً 1).
A..B يستثني A (الـ commits بعد A حتى B). A^..B يشمل A (الـ commits من A إلى B ضمنًا).
إن لم يُدفع: git reset --hard HEAD~1. إن دُفع: git revert <commit> لإنشاء commit يتراجع عنه.
cherry-pick لـ commits محددة. rebase لنقل فروع كاملة. إن احتجت معظم commits الفرع، فـ rebase أنظف.