We are still cooking the magic in the way!
المستودعات البعيدة والتعاون
المستودعات البعيدة والتعاون
كل أمر نفّذته حتى الآن — commit وbranch وmerge وrebase — يعمل بالكامل داخل مستودعك المحلي. في اللحظة التي تحتاج فيها إلى مشاركة العمل مع مهندس آخر أو مع منظومة CI/CD أو خط أنابيب النشر، يجب أن تفهم المستودعات البعيدة (Remotes): ما هي، وكيف يتتبعها Git، والآليات الدقيقة لـfetch وpull وpush. في شركات كـGitHub وShopify وStripe، تتعاون عشرات الفرق على ملايين الـ commits باستخدام هذه الأساسيات بالضبط.
ما هو المستودع البعيد فعلاً
المستودع البعيد ليس سوى عنوان URL مُخزَّن بإسم في .git/config. لا يوجد سحر في Git — origin مجرد اصطلاح وليس كلمة مفتاحية. يمكنك أن لا يكون لديك أي remote، أو واحد، أو عدة. لكل remote اسم (origin أو upstream أو backup) وعنوان URL (HTTPS أو SSH). عند git clone، ينشئ Git تلقائياً remote باسم origin يشير إلى العنوان الذي استنسخت منه.
داخلياً، يُخزِّن .git/config هذه المعلومات كأقسام INI بسيطة. عناوين URL مجرد نصوص — يحلّها Git وقت الاتصال بالشبكة عبر البروتوكول المناسب (SSH أو HTTPS أو بروتوكول git:// غير المصادَق، الذي لا يُستخدم في الإنتاج كاد).
فروع التتبع البعيدة (Remote-Tracking Branches)
بعد عملية fetch، يُخزِّن Git ما تعلمه عن المستودع البعيد في فروع التتبع البعيدة — مراجع للقراءة فقط تحت refs/remotes/origin/. هذه نسخة مؤقتة محلية من حالة المستودع البعيد في آخر مرة نفّذت فيها fetch. لا يمكنك الانتقال إليها مباشرةً؛ وجودها يُمكِّنك من المقارنة والدمج دون الحاجة للاتصال بالشبكة مجدداً.
origin/main ما بدا عليه main في المستودع البعيد آخر مرة نفّذت فيها git fetch. دفع زميلك قبل خمس دقائق غير مرئي لك حتى تُنفِّذ fetch من جديد. هذا تصميم مقصود — Git نظام يعمل في وضع عدم الاتصال أولاً.
fetch مقابل pull: الفرق الجوهري
git fetch يُنزِّل الكائنات الجديدة ويُحدِّث فروع التتبع البعيدة. لا يُغيِّر شيئاً في شجرة العمل أو الفروع المحلية. git pull اختصار لـgit fetch متبوعاً فوراً بـgit merge أو git rebase (حسب الإعداد). في كبريات شركات التقنية، يفضّل كثير من المهندسين المخضرمين تنفيذ fetch صريحاً ثم المراجعة ثم الدمج، بدلاً من pull، لأن ذلك يمنحهم فرصة رؤية ما قادم قبل تطبيقه.
git config --global fetch.prune true مرة واحدة ونسَ الأمر. بذلك ستُنظِّف كل عملية git fetch تلقائياً فروع التتبع البعيدة القديمة (الفروع المحذوفة من البعيد). بدون هذا، يمتلئ git branch -r بمراجع وهمية بمرور الوقت، مما يُربك القادمين الجدد ويُبطئ إكمال الأوامر.
push: إرسال عملك إلى المستودع البعيد
git push يُرفع كائنات محلية إلى البعيد ويطلب منه تقديم مؤشر الفرع. يقبل البعيد فقط إذا كان الـ push يُمثِّل fast-forward على البعيد — أي أن سلسلة الأجداد للـ commit الجديد تتضمن الطرف البعيد الحالي. إذا تقدّم البعيد منذ آخر fetch، يرفض Git الـ push بخطأ non-fast-forward، مُجبِراً إياك على الدمج أولاً.
git push --force أبداً على فرع مشترك. يُلغي --force المحتوى البعيد دون شرط، مُدمِّراً commits ربما سحبها زملاؤك بالفعل. استخدم --force-with-lease بدلاً من ذلك: يتضمن فحصاً بأن مرجع التتبع البعيد الخاص بك يطابق الطرف البعيد الفعلي. إذا دفع شخص آخر منذ آخر fetch، يُرفض الـ push — مما يمنع فقدان البيانات الصامت. تُضبط كثير من بيئات استضافة Git لرفض --force على الفروع المحمية.
فروع التتبع بعمق
فرع التتبع (أو الـ upstream branch) هو فرع محلي مضبوط لتتبع فرع تتبع بعيد. هذه العلاقة تُخبر Git بشيئين: أين يدفع افتراضياً، وكم أنت متقدم أو متأخر. يعرض Git هذه المعلومات في git status وفي git branch -vv.
سير عمل Fork والـ Upstream
تستخدم المشاريع مفتوحة المصدر وكثير من البيئات المؤسسية سير عمل Fork: لا تدفع مباشرةً إلى المستودع الأصلي. بدلاً من ذلك تنشئ نسخة (fork) منه على منصة الاستضافة، تستنسخ نسختك، ثم ترسل طلبات pull/merge إلى المستودع الأصلي. هذا هو النموذج القياسي على GitHub وGitLab وBitbucket لأي مشروع لا تملك فيه صلاحية الكتابة المباشرة.
المفتاح هو تضبيط remote-ين في نسختك المحلية المستنسخة: origin يشير إلى نسختك (حيث تدفع)، وupstream يشير إلى المستودع الأصلي (حيث تجلب التحديثات).
أنماط الفشل الشائعة
- النسيان في المزامنة قبل إنشاء الفرع. إذا أنشأت فرعاً من
mainقديمة دون جلب upstream أولاً، فرع ميزتك مبني على كود قديم. نفّذ دائماًgit fetch upstream && git merge upstream/mainقبل قطع فرع جديد. - رفض non-fast-forward.
error: failed to push some refsتعني أن البعيد لديه commits لم تحصل عليها محلياً. الحل دائماً نفسه:git fetch origin، ادمج أو أعد الأساس على العمل الوارد، ثم ادفع مجدداً. - فروع التتبع البعيدة القديمة. بعد أن يحذف زميل فرعاً على البعيد، لا يزال
git branch -rيُظهره حتى تنفّذgit fetch --prune. فعِّل الحذف التلقائي عالمياً:git config --global fetch.prune true. - الدفع إلى remote خاطئ. في سير عمل Fork، تحقق دائماً من
git remote -vقبل الدفع. الدفع إلىupstreamبدلاً منoriginسيحاول الكتابة إلى مستودع قد لا تملك صلاحيته، أو ربما تملكه لكن لا ينبغي تلويثه مباشرةً. - تباعد main في نسختك عن upstream. إذا تباعد
mainفي نسختك عن upstream (بسبب commit مباشر خاطئ)، استخدمgit reset --hard upstream/mainثم force push إلى main في نسختك لإعادة المحاذاة. هذه هي الحالة الوحيدة التي يكون فيها force push مقبولاً — لأنك تعيد ضبط main في نسختك الخاصة فحسب.