git pull
الجلب من مستودع آخر أو فرع محلي والدمج معه
يجلب الأمر 'git pull' المحتوى من مستودع بعيد ويدمجه فورًا في فرعك المحلي. هو في جوهره 'git fetch' يليه 'git merge' (أو 'git rebase' مع الخيار --rebase). وهو الطريقة الأشيع لمزامنة مستودعك المحلي مع تغييرات الآخرين. حين تشغّل git pull، ينزّل Git أولًا كل الـ commits الجديدة من المستودع البعيد، ثم يدمجها في فرعك الحالي. إن كان فرعك متأخرًا فقط، يتقدّم بـ fast-forward؛ وإن كان لدى الطرفين commits جديدة، يتوقف Git الحديث ويطلب منك الاختيار بين merge وrebase (--no-rebase / --rebase، أو إعداد pull.rebase). وإن وُجدت تغييرات متعارضة، يتوقف Git ويطلب منك حل التعارضات قبل إكمال الدمج.
الصيغة
git pull [--rebase | --no-rebase] [--ff-only | --ff | --no-ff] [--commit | --no-commit] [--autostash | --no-autostash] [-q | --quiet] [-v | --verbose] [--depth=<depth>] [--prune] [--tags | --no-tags] [--recurse-submodules[=yes|on-demand|no]] [<repository> [<refspec>...]]الخيارات
اختيار الخيار المناسب
استراتيجية السحب: merge أم rebase
الاختيار الأساسي الذي يؤثر في تاريخ الـ commits
| الأمر | ينشئ commit دمج | أسلوب التاريخ | الأنسب لـ |
|---|---|---|---|
git pull | يعتمد على الإعدادات (يفشل عند التباعد دون إعداد) | يحدده pull.rebase / pull.ff | fast-forward حين تكون متأخرًا فقط |
git pull --rebase | No | خطي | فروع الميزات، تاريخ نظيف |
git pull --no-rebase | نعم (عند التباعد) | يحافظ على الفروع | تجاوز إعداد rebase وفرض merge |
git pull --ff-only | No | خطي (يفشل عند التباعد) | ضمان عدم حدوث دمج عرضي |
خيارات الأمان والتحكم
خيارات لتجنّب الأخطاء والحفاظ على التحكم
| الأمر | يمنع | السلوك | متى تستخدمه |
|---|---|---|---|
--ff-only | عمليات دمج غير متوقعة | يفشل إن تعذّر fast-forward | CI/CD، الفروع المحمية |
--no-commit | commit تلقائي | يدمج لكنه يتوقف قبل الـ commit | مراجعة الدمج قبل الحفظ |
--autostash | أخطاء مجلد العمل المعدَّل | Stash ← pull ← pop | مزامنة سريعة مع عمل غير محفوظ |
--dry-run | أي تغييرات | يعرض ما سينزّله fetch؛ دون دمج | معاينة المراجع الواردة |
ما الذي يُجلب
التحكم في المراجع والتاريخ الذي يُنزَّل
| الأمر | يجلب الوسوم | يجلب التاريخ الكامل | حالة الاستخدام |
|---|---|---|---|
git pull | تلقائي (الوسوم المتتبَّعة) | نعم | سير العمل المعتاد |
--tags | كل الوسوم | نعم | مزامنة الإصدارات |
--no-tags | No | نعم | توفير البيانات، مزامنة الفرع فقط |
--depth=N | تلقائي (الوسوم المتتبَّعة) | آخر N من الـ commits فقط | المستودعات الكبيرة، بناء CI |
--unshallow | تلقائي (الوسوم المتتبَّعة) | يحوّل السطحي إلى كامل | تحتاج إلى التاريخ الكامل بعد استنساخ سطحي |
إدارة المستودعات البعيدة والفروع
خيارات للتعامل مع عدة مستودعات بعيدة ومراجع قديمة
| الأمر | النطاق | ينظّف | السيناريو |
|---|---|---|---|
git pull origin main | مستودع بعيد/فرع واحد | No | سحب عادي من origin |
--all | كل المستودعات البعيدة | No | المزامنة من origin + upstream |
--prune | مستودع بعيد واحد | الفروع المحذوفة | إزالة مراجع التتبّع القديمة |
حالات متقدمة
خيارات للحالات المعقّدة أو غير المعتادة
| الأمر | يحل | مستوى الخطر | الحالة المعتادة |
|---|---|---|---|
--allow-unrelated-histories | لا سلف مشترك | متوسط | دمج مستودعين منفصلين |
-s <strategy> | احتياجات دمج خاصة (لا يمنع التعارضات) | منخفض | فرض خوارزمية دمج محددة |
--recurse-submodules | وحدات فرعية قديمة | منخفض | مشاريع فيها وحدات git فرعية |
أمثلة على سير العمل
git statusتحقّق من التغييرات غير المحفوظة التي قد تتعارض
git stashخبّئ العمل غير المحفوظ إن لزم (أو استخدم --autostash)
git pull --rebase origin mainاسحب مع rebase ليبقى التاريخ نظيفًا
git stash popاستعد عملك المخبّأ إن كنت خبّأته سابقًا
git checkout feature-branchانتقل إلى فرع ميزتك
git pull --no-rebase origin mainادمج أحدث main في فرع ميزتك (صراحةً، لأن الفرعين تباعدا)
git push origin feature-branchادفع فرع الميزة المحدَّث
git fetch originنزّل التغييرات البعيدة دون تعديل مجلد العمل
git log HEAD..origin/mainاعرف الـ commits التي ستسحبها
git diff HEAD...origin/mainراجع التغييرات التي أُجريت على المستودع البعيد
git pull origin mainاسحب حين تكون راضيًا عن التغييرات
git pull --no-rebase origin mainجرّب سحبًا بـ merge - قد ينتج عنه تعارضات
git statusاعرف الملفات المتعارضة (المعلَّمة 'both modified')
(edit conflicted files)افتح الملفات وحلّ علامات التعارض (<<<<<<<، =======، >>>>>>>)
git add <resolved-files>جهّز الملفات المحلولة
git commitأكمل الدمج بـ commit
git pull --rebase --autostash origin mainخبّئ التغييرات تلقائيًا، واسحب، ثم أعد تطبيقها
حل المشكلات
Your local changes would be overwritten by merge
السبب: لديك تغييرات غير محفوظة في ملفات سيعدّلها السحب
احفظ تغييراتك أولًا (git add . && git commit)، أو خبّئها (git stash)، أو استخدم git pull --rebase --autostash
git stash && git pull && git stash popRefusing to merge unrelated histories
السبب: ليس للمستودعين البعيد والمحلي سلف مشترك (مثلًا عند السحب إلى مستودع أُنشئ للتو)
اسمح بدمج تواريخ لا علاقة بينها، وهذا شائع عند إضافة مستودع بعيد إلى مستودع محلي موجود
git pull --allow-unrelated-histories origin mainتعارض دمج في ملف أو أكثر
السبب: عدّلت أنت والمستودع البعيد الأسطر نفسها في ملف
افتح الملفات المتعارضة، وابحث عن العلامات (<<<<<<<، =======، >>>>>>>)، وعدّلها لحلّها، ثم git add وgit commit. أو ألغِ بـ git merge --abort
git add <resolved-file> && git commitNot possible to fast-forward, aborting
السبب: استخدمت --ff-only (أو ضُبط pull.ff=only) لكن فرعك المحلي تباعد عن البعيد
استخدم rebase بدلًا منه (git pull --rebase) أو اسمح بـ commit دمج (git pull --no-rebase)
git pull --rebase origin mainCannot pull with rebase: You have unstaged changes
السبب: يحتاج السحب بـ rebase إلى شجرة عمل نظيفة، ولديك تعديلات غير محفوظة
احفظ تغييراتك أو خبّئها، أو استخدم autostash للتعامل معها تلقائيًا
git pull --rebase --autostashNo tracking information for the current branch
السبب: فرعك غير مضبوط لتتبّع فرع بعيد
عيّن فرع الـ upstream صراحةً، أو حدد المستودع البعيد والفرع في أمر السحب
git branch --set-upstream-to=origin/main main'origin' does not appear to be a git repository
السبب: لا يوجد مستودع بعيد مضبوط باسم 'origin'
تحقّق من مستودعاتك البعيدة بـ git remote -v، ثم أضف origin أو استخدم اسم المستودع البعيد الصحيح
git remote add origin <url>You have divergent branches and need to specify how to reconcile them
السبب: لدى الطرفين commits جديدة ولم يُضبط pull.rebase ولا pull.ff، فيرفض Git الحديث التخمين (كانت الإصدارات 2.27+ الأقدم تحذّر فقط)
حدد merge (--no-rebase) أو rebase (--rebase)، أو اضبط قيمة افتراضية بـ git config pull.rebase
git config --global pull.rebase trueنصائح وأخطاء شائعة
أفضل الممارسات
- ✓راجع git status دائمًا قبل السحب لتجنّب التعارض مع تغييرات غير محفوظة
- ✓استخدم git pull --rebase للحفاظ على تاريخ نظيف وخطي في فروع الميزات
- ✓اضبط pull.rebase=true على مستوى النظام إن كنت تفضّل rebase افتراضيًا: git config --global pull.rebase true
- ✓استخدم git fetch أولًا حين تريد مراجعة التغييرات قبل دمجها
- ✓استخدم --ff-only حين تريد ضمان عدم إنشاء commits دمج بالخطأ
- ✓اضبط تتبّع الفرع بـ git push -u عند أول دفع لتبسيط عمليات السحب اللاحقة
- ✓استخدم --autostash حين تكون لديك تغييرات غير محفوظة وتحتاج إلى السحب بسرعة
- ✓اسحب من main/master بانتظام لتجنّب عمليات دمج كبيرة ومعقّدة لاحقًا
- ✓حلّ التعارضات فورًا - لا تترك مستودعك في حالة تعارض أبدًا
- ✓استخدم git pull --prune لتنظيف فروع التتبّع البعيد القديمة
- ✓فكّر في استخدام git fetch + git merge لتحكّم أكبر في عملية الدمج
- ✓تحقّق دائمًا أنك على الفرع الصحيح قبل السحب لتجنّب خلط التغييرات
أخطاء متكررة
- ✗السحب مع تغييرات غير محفوظة: قد يسبب هذا تعارضات أو يفشل تمامًا. احفظ تغييراتك في commit أو خبّئها أولًا، أو استخدم --autostash للتعامل معها تلقائيًا.
- ✗عدم فهم الفرق بين pull وfetch: 'git pull' يدمج تلقائيًا، وهذا قد يفاجئك. استخدم 'git fetch' أولًا إن أردت مراجعة التغييرات قبل دمجها.
- ✗استخدام merge حين يكون rebase أنظف: في فروع الميزات، ينشئ 'git pull --rebase' تاريخًا خطيًا أنظف دون commits دمج غير ضرورية.
- ✗تجاهل تعارضات الدمج: بعد سحب فيه تعارضات، يجب أن تحلّها وتحفظها. لا تترك مستودعك في حالة تعارض أبدًا.
- ✗السحب إلى الفرع الخطأ: تحقّق دائمًا من فرعك الحالي بـ 'git status' قبل السحب. السحب إلى main بينما قصدت فرع ميزة قد يسبب مشكلات.
الأسئلة الشائعة
يكتفي git fetch بتنزيل الـ commits الجديدة من المستودع البعيد دون تعديل مجلد عملك أو فروعك المحلية. أما git pull فينفّذ fetch ثم يدمج (أو يعيد التأسيس على) تلك التغييرات تلقائيًا في فرعك الحالي. استخدم fetch حين تريد مراجعة التغييرات قبل دمجها.
استخدم --rebase حين تريد تاريخًا نظيفًا وخطيًا (خصوصًا في فروع الميزات). يعيد هذا تطبيق commits المحلية فوق الـ commits المجلوبة بدل إنشاء commit دمج. واستخدم السحب العادي (merge) حين تريد الحفاظ على التاريخ الدقيق لوقت حدوث التغييرات.
يحدث fast-forward حين لا يحتوي فرعك المحلي على commits جديدة ليست في المستودع البعيد. فيحرّك Git مؤشر فرعك إلى الأمام ليطابق البعيد - دون حاجة إلى commit دمج. إن كانت لديك commits محلية، فعلى Git إما إنشاء commit دمج أو تنفيذ rebase - وما لم تمرّر --rebase/--no-rebase أو تضبط pull.rebase، يتوقف Git الحديث برسالة 'Need to specify how to reconcile divergent branches'.
استخدم git pull --rebase لإعادة تطبيق commits المحلية فوق الـ commits البعيدة، فينشأ تاريخ خطي. أو استخدم git pull --ff-only الذي لا ينجح إلا إن أمكن fast-forward (يفشل إن كانت لديك commits محلية متقدّمة).
يعتمد ذلك. مع سحب بـ merge، يسمح Git بذلك إن لم تمس الـ commits الواردة الملفات التي عدّلتها؛ وإلا يرفض برسالة 'Your local changes ... would be overwritten by merge'. ومع --rebase، أي تغيير غير محفوظ يمنع السحب. أفضل ممارسة: احفظ تغييراتك أولًا، أو استخدم git pull --rebase --autostash لتخبئتها واستعادتها تلقائيًا.
يوقف Git الدمج مؤقتًا ويعلّم الملفات المتعارضة. افتح كل ملف متعارض، وابحث عن علامات التعارض (<<<<<<<، =======، >>>>>>>)، وعدّله لحلّه، ثم نفّذ git add على الملف وgit commit لإكمال الدمج. استخدم git merge --abort للإلغاء (أو، مع git pull --rebase، git rebase --continue / git rebase --abort).
بعد السحب مباشرة، شغّل git reset --hard ORIG_HEAD - يحفظ Git رأسك السابق في ORIG_HEAD في عمليات الدمج وfast-forward وrebase. لا تستخدم HEAD~1: فقد يكون fast-forward جلب عدة commits. ويتخلّص --hard أيضًا من التغييرات غير المحفوظة. وإن تحرّك ORIG_HEAD منذ ذلك، فاعثر على الرأس القديم بـ git reflog.
يعني هذا عادةً أنك تسحب من الفرع أو المستودع البعيد الخطأ. تحقّق: git branch -vv لرؤية معلومات التتبّع، وgit remote -v للتأكد من المستودعات البعيدة، وgit fetch --all ثم git log origin/main لرؤية الـ commits البعيدة.
يحدد git pull origin main صراحةً المستودع البعيد والفرع اللذين تسحب منهما. أما git pull (دون وسائط) فيستخدم فرع التتبّع المضبوط لفرعك الحالي. وإن لم يُضبط التتبّع، يظهر خطأ يطلب منك تحديدهما.
على مستوى النظام: git config --global pull.rebase true (لـ rebase) أو git config --global pull.rebase false (لـ merge). ويمكنك أيضًا ضبطه لكل مستودع دون --global، أو لكل فرع بـ git config branch.<name>.rebase true.