ما هو المستودع البعيد؟
كل ما فعلته حتى الآن يعيش في .git على جهازك. المستودع البعيد (Remote) نسخة أخرى من نفس المستودع في مكان آخر، غالبًا على GitHub أو GitLab، يرفع إليها الجميع ويسحبون منها. Git لا يعتبرها "الأصل" تقنيًّا: هي مجرّد نسخة أخرى لها اسم وعنوان، والفريق يتّفق أن يعامل إحداها كمرجع مشترك.
الربط بـ GitHub: المصادقة أولًا
GitHub لا يقبل كلمة مرور حسابك في الطرفية منذ 2021. لديك ثلاث طرق، اختر واحدة:
| الطريقة | الإعداد | ملاحظات |
|---|---|---|
| GitHub CLI | gh auth login ثم اتبع الخطوات | الأسهل: يضبط كل شيء لـ HTTPS تلقائيًّا |
| SSH | أنشئ مفتاحًا وأضفه لحسابك (أدناه) | لا رموز تنتهي صلاحيتها |
| رمز وصول (Token) | أنشئه من إعدادات المطوّر في GitHub، والصقه مكان كلمة المرور | احفظه في مدير كلمات المرور؛ لا تضعه في الكود |
إعداد SSH مرة واحدة لكل جهاز:
ssh-keygen -t ed25519 -C "baraa@example.com" # Enter للمسار الافتراضي
cat ~/.ssh/id_ed25519.pub # انسخ المفتاح العام كاملًا
# الصقه في GitHub ← Settings ← SSH and GPG keys ← New SSH key
ssh -T git@github.com # اختبار: Hi username! ...
id_ed25519.pub (بـ .pub) هو المفتاح العام الذي تشاركه. الملف بلا .pub مفتاحك الخاص: لا يغادر جهازك أبدًا.
رفع مشروع محلي إلى GitHub
أنشئ مستودعًا فارغًا على GitHub (بلا README، حتى لا يبدأ بتاريخ مختلف عن تاريخك)، ثم:
git remote add origin git@github.com:user/repo.git
git push -u origin main
To github.com:user/repo.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.
originاسم مستعار للعنوان، وهو العُرف لا كلمة محجوزة.-u(أو--set-upstream) تربطmainالمحلي بـmainعلىorigin. بعدها يكفيgit pushوgit pullبلا أي وسائط.
git remote -v # الأسماء والعناوين
وإن نسخت المستودع بـ git clone، فـ origin والربط مضبوطان تلقائيًّا (درس الاستنساخ).
الفروع المتتبِّعة ونسخة origin/main
هنا الفكرة التي تفسّر كل سلوك fetch وpull. عندك فرعان لكل فرع بعيد:
main: فرعك المحلي، تعمل عليه.origin/main: نسخة محلية للقراءة فقط من آخر ما رأيته فيmainعلى GitHub. لا تتحدّث وحدها؛ تتحدّث فقط حين تتواصل مع البعيد.
git branch -vv
* main 7ee3dfb [origin/main: ahead 1] My work
ahead 1: عندك commit لم ترفعه. لكن انتبه: هذه المقارنة مع origin/main كما رأيته آخر مرة، لا مع GitHub الآن. لو رفع زميلك شيئًا قبل ساعة، لا يعرف Git ذلك بعد. وهذا هو سبب أن git status قد يقول "up to date" وأنت متأخّر فعلًا.
fetch: انظر قبل أن تدمج
git fetch
aa06f56..727d3b3 main -> origin/main
fetch تنزّل الجديد من البعيد وتحدّث origin/main، ولا تلمس فرعك ولا ملفاتك. آمنة دائمًا. الآن تعرف الحقيقة:
git branch -vv
* main 7ee3dfb [origin/main: ahead 1, behind 1] My work
git log --oneline main..origin/main # ما عندهم وليس عندي
git diff main origin/main # الفرق في الكود
pull = fetch + دمج
git pull
pull تفعل fetch ثم تدمج origin/main في main مباشرة. أسرع، لكنك تدمج دون أن ترى. عمليًّا:
pullلفرعك اليومي حين تثق بما سيأتي.fetchثم مراجعة ثم دمج، حين تريد أن ترى ماذا تغيّر أولًا، أو قبل عمل حسّاس.
حين يختلف التاريخان
إن رفع زميلك commit وعندك commit لم ترفعه، فالتاريخان تفرّعا. حينها قد يتوقّف git pull ويطلب منك اختيار طريقة التوفيق:
hint: You have divergent branches and need to specify how to reconcile them.
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
false تضيف commit دمج، وtrue تضع commits فوق ما سحبته فيبقى التاريخ مستقيمًا (درس rebase). اضبط واحدًا عالميًّا مرة واحدة (درس الإعداد).
push المرفوض
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to 'github.com:user/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.
الرفض يحميك: البعيد فيه commits ليست عندك، والرفع كان سيمحوها. الحل ليس --force، بل اسحب أولًا (git pull)، حلّ أي تعارض، ثم ارفع.
دورة العمل اليومية
git switch main
git pull # ابدأ من أحدث نسخة
git switch -c feature/search # فرع للمهمة
# ... عمل و commits ...
git push -u origin feature/search # أول رفع للفرع
git push # الرفعات التالية
ثم تفتح Pull Request من هذا الفرع (درس طلبات السحب).
إدارة الفروع البعيدة
git branch -r # الفروع البعيدة التي تعرفها
git branch -a # المحلية والبعيدة معًا
git push origin --delete old-branch # احذف فرعًا من GitHub
git fetch --prune # احذف origin/... لفروع حُذفت من البعيد
بلا --prune، تبقى عندك origin/feature-x لفرع حذفه زميلك من شهور. اجعله افتراضيًّا: git config --global fetch.prune true.
أكثر من مستودع بعيد
git remote add upstream https://github.com/original/repo.git # للمساهمة في مشروع غيرك
git remote rename origin github
git remote set-url origin git@github.com:user/repo.git # من HTTPS إلى SSH
git remote remove backup
upstream عُرف شائع للمستودع الأصلي حين تعمل على نسخة منه (Fork)، كما في درس طلبات السحب. ويمكنك تجميع عدّة مستودعات في مجموعة وتحديثها معًا:
git config remotes.all "origin backup"
git remote update all # fetch من الاثنين
أخطاء شائعة
- كلمة مرور الحساب عند الرفع بـ HTTPS: مرفوضة. استخدم
gh auth loginأو SSH أو رمز وصول. - مستودع GitHub بـ README ثم
pushلمشروع محلي: التاريخان مختلفان من البداية فيُرفض الرفع. أنشئه فارغًا، أو اسحب أولًا بـgit pull --allow-unrelated-histories. - الثقة بـ "up to date" بلا
fetch: المقارنة مع آخر ما رأيت، لا مع البعيد الآن. push --forceلتجاوز الرفض: يمحو عمل زملائك. اسحب أولًا.- نسيان
-uفي أول رفع لفرع: كلgit pushبعدها يطلب تحديد الوجهة. - مشاركة المفتاح الخاص أو رمز الوصول: في رسالة أو في الكود. المفتاح العام فقط (
.pub) يُشارك.
🎯 التالي: GitHub وطلبات السحب (Pull Requests).