Pull request في Git: ما هو وكيف تنشئ PR على GitHub
pull request (PR) طلب دمج فرعك في الفرع الرئيسي لمستودع GitHub: تعرض التغييرات، ويناقشها زملاؤك ويراجعونها، ثم يُدمج الفرع بعد الموافقة. يسمى الأمر نفسه في GitLab merge request (MR). وهو ميزة من المنصة وليس أمراً في Git، ولا علاقة له بالأمر git pull.
pull request (PR) اقتراح بدمج التغييرات من فرع إلى آخر، يُكتب على منصة مثل GitHub. ترسل فرعك إلى الخادم وتفتح PR، فيرى الفريق الفرق (diff) ويعلّق على الأسطر ويشغّل الفحوصات الآلية، ثم يضغط زر الدمج. وفي GitLab تُسمى الآلية نفسها merge request (MR). وإذا أردنا الإجابة باختصار عن سؤال «git pull request ما هو»: إنها نقطة التحقق بين «كتبت الكود» و«وصل الكود إلى main».
Git pull request ما هو، ومن أين جاء الاسم
نشأ الاسم تاريخياً. يطلب صاحب التغييرات من مالك المستودع أن «يسحب» (pull) فرعه إلى فرعه هو، ومن هنا جاء pull request. أما GitLab فاختار اسماً يصف النتيجة، وهو merge request أي طلب دمج. أما Bitbucket وAzure DevOps فتستخدمان التسمية pull request. والمعنى واحد: فرع مصدر، وفرع هدف، ووصف، ونقاش، وفحوصات، وزر دمج.
المهم أن تفهم أن pull request ليس جزءاً من Git. لا يوجد في Git كائن اسمه «PR»، ولا يمكن إنشاؤه بـ commit أو العثور عليه داخل المجلد .git. إنه كيان تابع للمنصة: يحفظ GitHub الوصف والتعليقات وحالات الفحوصات، بينما يهتم Git بالفروع والـ commits التي يتضمنها الـ PR فقط.
اختصار PR في حديث المطورين يعني تقريباً دائماً pull request: «أرسل لي PR»، و«PR للمراجعة»، و«دمجت الـ PR». أما في GitLab فيقولون MR.
الفرق بين pull request وgit pull
تختلط هذه الأمور بسبب تشابه الكلمات. الأمر git pull ينزّل الـ commits الجديدة من المستودع البعيد ويدمجها مباشرة في فرعك الحالي، وهو عملية محلية في الطرفية. أما pull request فصفحة ويب في GitHub أو GitLab أو Bitbucket تقترح دمج فرع في آخر.
| git pull | Pull request | |
|---|---|---|
| أين يعمل | أمر Git في الطرفية | صفحة على GitHub وGitLab وBitbucket |
| ماذا يفعل | يجلب التغييرات من الخادم إليك | يقترح دمج فرعك في فرع آخر أو مشترك |
| من يشارك فيه | أنت فقط | الكاتب والمراجعون وCI |
| هل يحتاج منصة | لا، يكفي remote | نعم |
لا يوجد أمر منفصل اسمه «git pull request» في Git. هناك أداة قديمة هي git request-pull، لكنها تولّد نص رسالة بريد يلخص التغييرات لإرساله، ولا علاقة لها بـ PR على GitHub.
لماذا نحتاج إلى pull request
ما دام المشروع يعمل عليه شخص واحد يمكن أن تُسجّل التغييرات مباشرة في main. لكن عندما يصبح في المستودع شخصان أو أكثر تصبح عمليات push المباشرة إلى الفرع الرئيسي مصدراً للبناء المكسور وفقدان العمل. يحل pull request عدة مشكلات دفعة واحدة:
- مراجعة الكود — يرى شخص ثانٍ التغييرات قبل أن تدخل main، ويلتقط الأخطاء التي فاتت الكاتب؛
- الفحوصات الآلية — يشغّل GitHub Actions أو أي CI آخر الاختبارات وأدوات الفحص عند كل PR، والحالة الحمراء تمنع دمج كود مكسور؛
- سجل القرارات — بعد سنة يمكنك من خلال الـ PR أن تفهم ليس فقط ما الذي تغيّر، بل لماذا، مع النقاش الذي دار حوله؛
- المساهمة في مشاريع الآخرين — في المشاريع مفتوحة المصدر ليست لديك صلاحية كتابة، والـ PR من fork هو الطريقة الوحيدة لاقتراح إصلاح؛
- حماية الفروع — قواعد حماية الفرع في GitHub يمكنها منع push المباشر إلى main واشتراط PR موافَق عليه.
كيف تنشئ pull request على GitHub من فرع
هذا هو السيناريو الأساسي للفريق الذي لدى جميع أعضائه صلاحية الكتابة في المستودع. يجري العمل في فروع feature، ولا يتغير main إلا عبر PR.
الخطوة 1. أنشئ فرعاً من main المحدَّث
git switch main
git pull
git switch -c feature/login-form
اجعل اسم الفرع دالاً على المحتوى: feature/… أو fix/… أو رقم المهمة. فيفهم المراجع فوراً موضوع التغييرات.
الخطوة 2. أنشئ الـ commits
git add src/login.js
git commit -m "إضافة نموذج تسجيل الدخول"
PR واحد لمهمة واحدة. الـ PR الصغير بين 100 و300 سطر يُراجَع بسرعة ودقة، أما PR بـ3000 سطر فيوافق عليه المراجع دون أن يقرأه.
الخطوة 3. أرسل الفرع إلى الخادم (git push لـ pull request)
git push -u origin feature/login-form
يربط العلم -u الفرع المحلي بالفرع البعيد، وبعد ذلك يكفي git push البسيط. وفي رد GitHub ستجد رابطاً لإنشاء PR:
remote: Create a pull request for 'feature/login-form' on GitHub by visiting:
remote: https://github.com/team/app/pull/new/feature/login-form
الخطوة 4. افتح PR في الواجهة
افتح الرابط من الطرفية، أو افتح المستودع على GitHub، فيظهر بعد الـ push الأخير شريط بزر «Compare & pull request». وهناك طريقة أخرى هي تبويب «Pull requests» ثم الزر «New pull request».
- تحقق من زوج الفروع: base وهو الفرع الذي سيُدمج فيه (عادةً
main)، وcompare وهو فرعك. - اكتب العنوان: ما الذي تم إنجازه، بصيغة أمر أو وصف مختصر.
- في الوصف اشرح السبب، وكيف يُختبر، وما الذي بقي خارج النطاق. إذا كان في المستودع قالب لـ PR فستُملأ الحقول تلقائياً.
- على اليمين عيّن المراجعين (Reviewers) والمسؤول (Assignee) والوسوم إن كان الفريق يستخدمها.
- اضغط «Create pull request» أو اختر المسودة (انظر أدناه).
إنشاء PR من الطرفية: GitHub CLI
إذا لم ترد الانتقال إلى المتصفح، فهناك الأداة الرسمية gh. وهي ليست أمراً من Git، بل برنامج مستقل من GitHub، لكنها مناسبة جداً لـ PR:
gh pr create --base main --title "إضافة نموذج تسجيل الدخول" --body "Closes #42"
gh pr list
gh pr checkout 57
gh pr merge 57 --squash
والجواب الصريح عن سؤال «ما أوامر git لـ pull request»: يعرف Git الفروع والـ commits وpush، أما PR فيُنشأ على المنصة، في المتصفح أو عبر gh أو عبر API.
كيف تُنشئ pull request إلى مستودع غيرك عبر fork
في المشاريع المفتوحة ليست لديك صلاحية كتابة. لذلك تُنشئ أولاً fork، أي نسختك الخاصة من المستودع على GitHub، وتعمل فيها ثم تقترح التغييرات على الأصل.
- في صفحة المشروع اضغط «Fork»، فيظهر لديك
github.com/you/project. - استنسخ الـ fork الخاص بك وأضف الأصل كـ remote ثانٍ، ويُسمى عادةً
upstream. - أنشئ فرعاً وسجّل الـ commits وأرسل الفرع إلى الـ fork الخاص بك.
- على GitHub افتح PR: base repository هو المشروع الأصلي، وhead repository هو الـ fork الخاص بك مع فرعك.
git clone git@github.com:you/project.git
cd project
git remote add upstream https://github.com/owner/project.git
git switch -c fix/typo-readme
git commit -am "إصلاح خطأ مطبعي في README"
git push -u origin fix/typo-readme
قبل أن تبدأ ألقِ نظرة على الملف CONTRIBUTING.md: يصف عادةً قواعد كتابة الـ commits والاختبارات، وهل يجب إنشاء issue أولاً. وحافظ على تحديث الـ fork: نفّذ git fetch upstream ثم git rebase upstream/main في فرعك، حتى لا يتأخر PR عن الأصل.
Merge request في GitLab: ما هو وكيف تنشئه
merge request في منصة GitLab نظير كامل لـ pull request. تختلف التسميات وتفاصيل الواجهة، لكن العملية واحدة: فرع، ثم push، ثم طلب دمج، ثم مراجعة، ثم دمج.
يمكنك إنشاء MR بعدة طرق:
- عبر الرابط الذي يطبعه GitLab في الطرفية بعد
git pushلفرع جديد؛ - في قسم Merge requests من المشروع بالزر «New merge request» مع اختيار الفرع المصدر والهدف؛
- مباشرة أثناء push باستخدام push options في GitLab، دون الدخول إلى المتصفح.
git push -o merge_request.create -o merge_request.target=main origin feature/login-form
مصطلحات GitLab مختلفة قليلاً: الموافقة تسمى approve، والمسؤول عن الدمج assignee، وبدلاً من GitHub Actions يعمل GitLab CI/CD بملف .gitlab-ci.yml. وتوجد المسودات أيضاً في GitLab وتسمى Draft.
مراجعة pull request
يفتح المراجع تبويب «Files changed» ويرى الفرق. يمكنه ترك تعليق على أي سطر، أو اقتراح تعديل جاهز (suggestion) يطبّقه الكاتب بزر واحد. تُجمَع التعليقات في مراجعة واحدة وتُرسَل معاً مع أحد الأحكام التالية:
- Comment — ملاحظات دون قرار؛
- Approve — التغييرات موافَق عليها؛
- Request changes — يجب تعديل شيء، ولا يُفضَّل الدمج.
المراجعة الجيدة تنظر إلى المنطق وسهولة القراءة والاختبارات والحالات الحدّية، ولا تجادل في الأذواق، فتنسيق الكود يُترك للمدقق (linter) في CI. ويُستحسن أن يرد الكاتب على كل تعليق: أصلحته، أو ناقشناه، أو نتركه كما هو مع التوضيح.
كيف تتحقق من PR لشخص آخر محلياً (git checkout pull request)
أحياناً تحتاج إلى تشغيل الكود عندك. إذا كان الفرع في المستودع نفسه يكفي git fetch ثم git switch. أما الـ PR القادم من fork فيوفر GitHub روابط خاصة هي pull/<الرقم>/head:
git fetch origin pull/57/head:pr-57
git switch pr-57
في GitLab تسمى الروابط المشابهة merge-requests/<الرقم>/head. أو ببساطة gh pr checkout 57 إذا كانت أداة GitHub CLI مثبتة.
كيف تحدّث pull request بعد الملاحظات
يرتبط PR بالفرع وليس بـ commits محددة. يكفي أن تُنشئ commits جديدة في الفرع نفسه وترسلها، فيتحدث PR تلقائياً دون الحاجة إلى إنشاء طلب جديد.
git commit -am "تطبيق ملاحظات المراجعة"
git push
Git rebase pull request: تحديث الفرع من main الجديد
بينما يكون PR قيد المراجعة يتقدم main إلى الأمام. إذا كتب GitHub أن الفرع قديم أو فيه تعارضات، فحدّثه. طريقة rebase تعطي سجلاً خطياً:
git fetch origin
git rebase origin/main
# حل التعارضات، ثم git add، ثم git rebase --continue
git push --force-with-lease
بعد rebase تتغير معرّفات الـ commits، لذلك سيُرفض push العادي ويلزم الدفع القسري. استخدم --force-with-lease: فهو يرفض الكتابة فوق الفرع إذا ظهرت فيه commits من شخص آخر. وإذا كان يعمل على الفرع أكثر من شخص، فالأكثر أماناً هو دمج main عبر git merge origin/main دون إعادة كتابة السجل.
كيف تدمج pull request: merge وsquash وrebase
عندما تتم الموافقة على المراجعة وتكون الفحوصات خضراء يمكن دمج PR. يعرض GitHub ثلاث طرق، ويستطيع مدير المستودع أن يُبقي بعضها فقط.
| الطريقة | ماذا يصل إلى main | متى تناسب |
|---|---|---|
| Create a merge commit | كل commits الفرع مع commit دمج | عندما تريد السجل الكامل ومعرفة الـ commits التي وصلت معاً |
| Squash and merge | commit واحد يضم كل تغييرات PR | عندما يحتوي الفرع على كثير من commits صغيرة مثل «fix typo»، ويهم أن يبقى سجل main نظيفاً |
| Rebase and merge | commits الفرع واحداً تلو الآخر دون commit دمج | عندما تكون الـ commits مرتبة وكل واحد منها مفيد بذاته |
دمج pull request عبر الواجهة هو في الجوهر git merge نفسه، لكنه منفَّذ على الخادم. بعد الدمج يقترح GitHub حذف الفرع، فوافق، إذ لم يعد لازماً. ثم نظّف النسخة المحلية:
git switch main
git pull
git branch -d feature/login-form
يمكن أيضاً دمج PR يدوياً من الطرفية: ادمج الفرع في main محلياً ثم أرسله. يلاحظ GitHub أن commits الفرع صارت في الفرع الهدف، فيعلّم الـ PR كمدموج تلقائياً. لكن بهذه الطريقة تضيع الفحوصات وقواعد حماية الفرع، ولذلك يُفضَّل في الفرق الدمج بالزر.
Auto-merge وmerge queue
إذا كانت الفحوصات تستغرق وقتاً طويلاً يمكنك تفعيل الدمج التلقائي: سيُدمج PR وحده عندما تتحقق كل الشروط. وفي المستودعات الكبيرة يُستخدم طابور دمج (merge queue) يفحص PR فوق ما هو موجود في الطابور، حتى لا ينكسر main بسبب تغييرات غير متوافقة.
مسودات pull request (Draft)
المسودة (Draft) هي PR لم يصبح جاهزاً للمراجعة بعد. لا يمكن دمجه، ولا يتلقى المراجعون طلب مراجعة. المسودات مفيدة لعرض الاتجاه مبكراً، أو لتشغيل CI، أو لجمع آراء حول البنية. في GitHub اختر خيار المسودة من القائمة المنسدلة لزر الإنشاء، أو نفّذ gh pr create --draft. وعندما ينتهي العمل اضغط «Ready for review». وفي GitLab تُعلَّم المسودة ببادئة Draft: في عنوان MR.
ربط pull request بالـ issues
إذا كتبت في وصف PR كلمة مفتاحية مع رقم المهمة، فبعد الدمج إلى الفرع الافتراضي يغلق GitHub الـ issue تلقائياً:
Closes #42
Fixes #17
Resolves #8
تعمل الكلمات close وfix وresolve بصيغها المختلفة (closes وfixed وresolves). مجرد ذكر #42 دون كلمة مفتاحية ينشئ رابطاً، لكنه لا يغلق المهمة. وفي GitLab تعمل بالطريقة نفسها العبارات مثل Closes #42.
هل يمكن حذف pull request أو merge request؟
المستخدم العادي لا يستطيع حذف PR على GitHub، بل يمكنه إغلاقه فقط بزر «Close pull request». يبقى الـ PR المغلق في السجل، ويمكن إعادة فتحه. أما الفرع فاحذفه بعد الإغلاق بشكل منفصل. الحذف الكامل للـ PR ممكن فقط عبر دعم GitHub، مثلاً إذا وصلت إليه أسرار مثل كلمات المرور.
في GitLab يستطيع الكاتب أو مشارك يملك صلاحيات إغلاق MR، أما الحذف فيملكه مالك المشروع أو المسؤول. وإذا وقعت كلمة مرور أو token داخل PR فالإغلاق لا يكفي: ألغِ السر فوراً، لأن الـ commits وصلت إلى الخادم بالفعل.
أخطاء شائعة مع pull request
- PR من main. عملت على main المحلي وفتحت PR منه. سيحتوي الـ PR التالي على التغييرات القديمة أيضاً. اعمل دائماً في فرع منفصل.
- فرع base خاطئ. فُتح PR إلى
developبدلاً منmainأو العكس. يمكن تغيير base بزر Edit بجوار عنوان PR. - دخول ملفات زائدة إلى الفرق. ملفات البناء، و
node_modules، و.env. أضفها إلى.gitignoreوأزلها من الفهرس بـgit rm --cached. - PR ضخم. قسّم المهمة إلى عدة PR متتابعة.
- push عادي بعد rebase. الخطأ
rejected (non-fast-forward). يلزمgit push --force-with-lease، وليس--force. - التعارضات. لا تحلها في المحرر على الويب بشكل أعمى، بل اسحب main محلياً وحلّها واختبر الكود.
Pull request في git flow وغيره من الأساليب
يتناسب pull request مع أي عملية جماعية. في GitHub Flow الأمر بسيط: فرع من main، ثم PR، ثم مراجعة، ثم دمج، ثم نشر. وفي git flow تُفتح PR إلى develop من فروع feature، وفروع الإصدار والـ hotfix تمر أيضاً عبر PR إلى main. وفي trunk-based development تكون PR قصيرة وتعيش ساعات لا أياماً. أياً كان الأسلوب، فالقاعدة واحدة: التغييرات في الفروع المشتركة تمر عبر pull request فقط.
الخلاصة
pull request آلية من المنصة وليس أمراً في Git: فرع أُرسل إلى الخادم، مع صفحة للنقاش والمراجعة والفحوصات. وفي GitLab يسمى merge request، وفي الحديث اليومي نقول PR وMR. أنشئ PR من فرع منفصل، واجعله صغيراً، وحدّثه بالـ push إلى الفرع نفسه، واختر طريقة الدمج التي تناسب سجل المشروع. تُشرح الفروع وpull request عملياً في دورة Git.
الأسئلة الشائعة
كم مراجعاً يحتاج pull request؟
عادةً يكفي واحد أو اثنان. الحد الأدنى للموافقات يُضبط في قواعد حماية الفرع، وما لم تُجمع هذه الموافقات يبقى زر الدمج غير متاح.
هل يمكن إنشاء pull request دون fork؟
نعم، إذا كانت لديك صلاحية الكتابة في المستودع، فأنشئ فرعاً فيه وافتح PR منه. الـ fork يلزم فقط عندما لا تملك صلاحية الكتابة.
ماذا أفعل إذا لم يراجع أحد PR لفترة طويلة؟
ذكّر المراجع بلباقة في تعليق أو في محادثة الفريق. في المشاريع المفتوحة قد يستغرق الانتظار أسابيع، فتحقق من أن PR يطابق قواعد CONTRIBUTING.md.
هل يمكن فتح pull request بين فرعين في الـ fork الخاص بي؟
نعم، في صفحة المقارنة اختر الـ fork الخاص بك كـ base وكـ head معاً. وهذا مفيد لمراجعة تغييراتك قبل إرسالها إلى المشروع الأصلي.
لماذا تظهر في PR commits لم أكتبها أنا؟
غالباً أُنشئ الفرع من main غير محدَّث أو اختير فرع base خاطئ. نفّذ rebase على main الجديد أو غيّر base من إعدادات PR.
يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Git من الصفر إلى مطور واثق».
- العمل الجماعي: النسخ المتفرعة، الفروع المميزة وطلبات السحب
- سير عمل Git في الفرق الحقيقية: أي سير عمل تختار