ما هو GitHub؟ الفرق بين Git وGitHub لمالكي VPS
تعرّف إلى الفرق العملي بين Git وGitHub: Git يعمل على جهازك أو خادمك، بينما GitHub خدمة مستضافة، مع مثال نشر واضح على VPS.
ما هو GitHub؟
GitHub خدمة مستضافة تخزّن مستودعات Git وتبني حولها موقعاً إلكترونياً. Git هو برنامج للتحكم في الإصدارات يعمل على حاسوبك أو خادمك. GitHub منتج لشركة واحدة مبني على Git، وتملكه Microsoft منذ 2018. يمكنك استخدام Git يومياً من دون فتح GitHub. ولا يمكنك استخدام GitHub من دون Git.
تكتسب هذه النقطة أهمية فور امتلاكك VPS (خادم افتراضي خاص). يسجّل Git تاريخ ملفات الإعداد وملفات النشر. ويحتفظ GitHub بنسخة من هذا التاريخ عندما لا يكون الخادم نفسه محتفظاً بها، كما يوفّر مكاناً لتشغيل عمليات البناء والمراجعات. يتتبع هذا الدليل مثالاً واحداً يبدأ من مجلد فارغ وينتهي بعملية نشر على خادم، ويعرّف كل مصطلح جديد عند ظهوره للمرة الأولى.
ما يفعله Git تلقائياً
Git هو نظام للتحكم في الإصدارات. يسجّل حالة دليل مع مرور الوقت، بحيث يمكنك معرفة ما الذي تغيّر ومتى ولماذا. كُتب في عام 2005 للعمل على نواة Linux. وهو موزّع، ما يعني أنّ كل نسخة من المستودع تحتوي على السجل الكامل. لا يعتمد تصميمه على خادم مركزي. وتكون نسخة المستودع على حاسوب محمول لأحد الزملاء مكتملة بقدر أي نسخة على خادم.
ثبّته واضبط هويتك. يرفض Git تسجيل commit من دون اسم وعنوان بريد إلكتروني، لأنّهما يُكتبان داخل commit نفسه.
sudo apt update && sudo apt install -y git
git --version
git config --global user.name "Your Name"
git config --global user.email "you@example.com"على Ubuntu 24.04، يعرض git --version الناتج git version 2.43.0. وتتصرف أي إصدارة من السنوات القليلة الماضية بالطريقة نفسها في كل ما يلي.
المثال: مستودع لملفات النشر على VPS
المستودع، الذي يُختصر عادةً إلى «repo»، هو دليل يراقبه Git. يصبح الدليل مستودعاً عند تشغيل git init، الذي ينشئ مجلد .git مخفياً داخله. هذا المجلد هو المستودع. احذف .git، وستبقى لديك بنية عادية لا تحتوي على أي سجل.
mkdir vps-deploy && cd vps-deploy
git init -b main
printf '.env\n*.key\n' > .gitignoreيسمّي -b main الفرع الأول main. إذا حذفت هذا الخيار، فسيعرض Git تلميحاً طويلاً حول اسم الفرع الافتراضي بدلاً من ذلك. يحدّد .gitignore المسارات التي يجب ألا يتتبّعها Git مطلقاً. أضف ملف الأسرار إليه منذ اليوم الأول، لأن الملف الذي يُجرى له commit مرة واحدة يبقى في السجل بعد حذفه، وإزالته بطريقة صحيحة تتطلب إعادة كتابة كل commit أُنشئ بعده.
Commits: وحدة سجل التغييرات
أضف الآن برنامجاً نصياً وسجّله.
printf '#!/bin/sh\nsudo systemctl restart caddy\n' > restart.sh
git add restart.sh .gitignore
git commit -m "Add restart script and gitignore"
git log --onelineينقل git add تغييراً إلى منطقة التجهيز، وهي قائمة العناصر التي ستدخل في الالتزام التالي. يكتب git commit هذه القائمة في السجل كإدخال واحد. يحتوي الالتزام على لقطة لكل ملف متتبَّع، ورسالة، واسم المؤلف، وطابع زمني، ومؤشر إلى الالتزام السابق. يطبع git log --oneline سطراً واحداً لكل التزام، ويبدأ كل سطر بتجزئة قصيرة مثل a1b2c3d. هذه التجزئة هي اسم الالتزام، وتقبلها معظم أوامر Git.
تجاوز خطوة git add، ثم يجيب git commit عن no changes added to commit (use "git add" and/or "git commit -a"). لا يوجد أي خلل. يخبرك Git بأن منطقة التجهيز فارغة، ولذلك لا يوجد شيء لإنشاء لقطة له. يُستخدم git status كلما لم تعرف الخطوة التالية: فهو يذكر الفرع الحالي، والتغييرات المجهزة، والملفات التي يستطيع Git رؤيتها لكنه لا يتتبعها.
الفروع: مسار ثانٍ في السجل
الفرع هو مؤشر متحرك إلى commit. يُعدّ main فرعاً، ولا يتمتع بأي خصائص خاصة في Git. لا تكلّفك عملية إنشائه شيئاً، لأن Git يكتب مؤشراً جديداً بدلاً من نسخ ملفاتك.
git switch -c add-backup
printf '#!/bin/sh\nrestic backup /srv\n' > backup.sh
git add backup.sh
git commit -m "Add nightly backup"
git switch main
lsبعد git switch main، لا يظهر backup.sh في القائمة. لم يُحذف أي شيء. الملف موجود في فرع add-backup، ولم يكن موجوداً في main، لذلك أزاله Git من دليل العمل عند انتقالك. يفاجئ هذا الجميع مرة واحدة. يعيده git switch add-backup.
المستودعات البعيدة: حيث يظهر GitHub أخيراً
جرت جميع الخطوات حتى الآن على جهاز واحد من دون أي شبكة. الـremote هو عنوان URL مسمّى لنسخة أخرى من المستودع نفسه. يستضيف GitHub إحدى هذه النسخ نيابةً عنك. الاسم التقليدي للمستودع البعيد الرئيسي هو origin.
أنشئ مستودعاً فارغاً عبر موقع GitHub، ثم اربطه. استخدم SSH بدلاً من HTTPS هنا إن أمكن: مفتاح SSH هو ملف تتحكم فيه، ولا تنتهي صلاحيته بالطريقة التي تنتهي بها صلاحية personal access token.
ssh-keygen -t ed25519 -C "vps-deploy"
cat ~/.ssh/id_ed25519.pub
ssh -T git@github.comالصق المفتاح العام المطبوع في صفحة مفاتيح SSH ضمن حسابك على GitHub، ثم أعد تشغيل الاختبار. يجيب المفتاح العامل بـ Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.. لا يمنحك GitHub shell، لذلك تمثل هذه الرسالة حالة النجاح. يعني git@github.com: Permission denied (publickey). أن مفتاحك لم يُرسَل أو لم يُقبل، فتحقق من أنك لصقت ملف .pub وليس المفتاح الخاص الموجود بجواره.
git remote add origin git@github.com:yourname/vps-deploy.git
git push -u origin mainيرسل git push عمليات commit إلى المستودع البعيد. ويسجل -u أن main المحلي يتتبع main البعيد، ولذلك يكفي لاحقاً استخدام git push المجرد. أما git clone <url> فهو العملية العكسية على جهاز جديد: ينسخ المستودع بأكمله مع سجله، ويضبط origin تلقائياً. يعمل remote عبر HTTPS أيضاً، وينتقل باستخدام البروتوكول نفسه الذي تستخدمه أي صفحة ويب، ما يساعد في الشبكات التي تحظر المنفذ الصادر 22. إذا احتاجت هذه الجملة إلى شرح، يوضّح ممّ يتكوّن طلب HTTP فعلياً الآلية.
طلبات السحب والمشكلات والتفرعات: الأجزاء الخاصة بـGitHub، وليست جزءاً من Git
كل ما سبق هو Git، ويعمل مع أي خادم. أما المصطلحات الثلاثة التالية فهي ميزات في GitHub. وتنسخها خدمات الاستضافة الأخرى، لكن Git نفسه لا يعرف شيئاً عنها.
طلب السحب (PR) هو طلب لدمج فرع في فرع آخر، ويُعرض في صفحة مخصصة للنقاش. تدفع add-backup، ثم تفتح طلب سحب يستهدف main، ويعرض الموقع الفروقات التزاماً بعد التزام. ويمكن للمستخدمين التعليق على أسطر محددة. وتعرض الفحوصات الآلية نتيجة النجاح أو الفشل بالنسبة إلى الفرع. عند النقر على الدمج، ينفّذ GitHub عملية الدمج على نسخته الخاصة، ثم يحدّث main. يأتي الاسم من سير العمل الأصلي، حيث كنت تطلب من المشرف أن يسحب فرعك إلى فرعه.
المشكلة هي سلسلة نقاش مرقّمة حول خطأ أو مهمة. تُخزَّن في قاعدة بيانات GitHub، لا في مستودعك. من المهم معرفة ذلك قبل اختيار خدمة الاستضافة: عند استنساخ المستودع، تحصل على جميع الالتزامات، لكنك لا تحصل على أي مشكلة. ولإخراج المشكلات، يجب استدعاء واجهة API.
التفرّع هو نسخة خاصة بك، على الخادم، من مستودع يملكه شخص آخر. تملك صلاحية الكتابة إلى النسخة، وتدفع فرعاً إليها، ثم تفتح طلب سحب من نسختك إلى المستودع الأصلي. بهذه الطريقة تساهم في مشروع لم يسمع مشرفوه عنك من قبل. والتفرّع هو نسخة مستنسخة موجودة على GitHub وتتذكر مصدرها.
تقرأ البرامج هذه العناصر الثلاثة عبر واجهة API نفسها التي يستخدمها الأشخاص. يراقب وكيل لمراجعة طلبات السحب تشغّله على خادمك طلبات السحب الجديدة، ويقرأ الفروقات، وينشر تعليقات على الأسطر. وتوجد اصطلاحات مثل ملف AGENTS.md في جذر المستودع لأن الأدوات تقرأ المستودع الآن إلى جانب الأشخاص.
ما الذي يفعله GitHub فعلياً لمالك VPS
ابدأ بتخزين الملفات خارج الخادم. يجب أن تكون نصوص النشر وملفات playbook في مكان مختلف عن الخادم الذي تُعدّه. أعد إنشاء VPS من صورة جديدة، ثم نفّذ الاستنساخ والتشغيل. اجعل ذلك المستودع خاصاً، وامنح الخادم deploy key: وهو مفتاح SSH مسجّل لمستودع واحد بدلاً من الحساب بالكامل، ومضبوط على القراءة فقط. إذا تسرّب deploy key للقراءة فقط، فسيكشف مستودعاً واحداً. أما إذا تسرّب مفتاح الحساب، فسيكشف كل ما يمكنك دفعه.
sudo git clone git@github.com:yourname/vps-deploy.git /srv/vps-deploy
cd /srv/vps-deploy
git pull --ff-onlyيرفض --ff-only إنشاء merge commit. على خادم يستهلك التغييرات فقط، يكون الدمج دائماً نتيجة غير مقصودة، لذلك يحوّل هذا الخيار السجل المربك إلى الخطأ الواضح fatal: Not possible to fast-forward, aborting.. هذا يعني أن شيئاً ما تغيّر على الخادم خلافاً لما ينبغي. اعثر عليه قبل أن تسحب التغييرات مرة أخرى.
إذا نفّذت الاستنساخ باستخدام root ثم شغّلت Git باستخدام مستخدم آخر، فستحصل على fatal: detected dubious ownership in repository at '/srv/vps-deploy'. يرفض Git قراءة مستودع يملكه مستخدم مختلف، لأن .git/config ضاراً يمكنه جعل Git يشغّل أوامر. أصلح الملكية باستخدام chown بدلاً من إضافة استثناء safe.directory، لأن الاستثناء يعطّل الفحص من دون إزالة السبب.
GitHub Actions: مسارات البناء والنشر
Actions هو نظام CI/CD في GitHub (التكامل المستمر والتسليم المستمر). أودِع ملف YAML ضمن .github/workflows/، وسيشغّله GitHub عند وقوع الحدث الذي حددته.
name: check
on:
push:
branches: [main]
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: sudo apt-get update && sudo apt-get install -y shellcheck
- run: shellcheck *.shالملف هو workflow. يعمل job على جهاز واحد. أما step فهو أمر واحد أو action منشورة واحدة. يستدعي uses: action من مستودع آخر، ويثبّت @v7 إصدارها الرئيسي (الإصدار v7 هو الحالي لـ actions/checkout اعتباراً من August 2026). ثبّت دائماً إصداراً ما، لأن action غير المثبّتة تعني تشغيل تعليمات برمجية لم تقرأها، مع إمكانية وصولها إلى أسرارك.
يطلب runs-on: ubuntu-latest من GitHub توفير آلة افتراضية جديدة، ويتم التخلص منها عند انتهاء job. تكون runners القياسية مجانية في المستودعات العامة، وتتضمن الخطة المجانية 2,000 دقيقة شهرياً للمستودعات الخاصة اعتباراً من August 2026. تحقّق من صفحة الأسعار الحالية قبل إعداد ميزانية تستند إلى هذا الرقم.
تُخزَّن الأسرار في إعدادات المستودع، وتُقرأ عبر ${{ secrets.DEPLOY_KEY }}. يحصل workflow الذي يشغّله pull request من fork على token للقراءة فقط، ولا يمكنه الوصول إلى تلك الأسرار؛ وإلا فسيتمكن شخص غريب من فتح PR تكون مهمته الوحيدة طباعتها.
تشغيل Actions runner على VPS تملكه
يرسل runs-on: self-hosted المهمة إلى جهاز تملكه بدلاً من ذلك. تعرض صفحة إعدادات runner في المستودع سطر التنزيل، وعنوان الويب للمستودع، وregistration token صالحاً لمدة ساعة واحدة. ضع العنصرين الأخيرين في REPO_URL وRUNNER_TOKEN، ثم يصبح الإعداد عبارة عن 3 أوامر.
./config.sh --url "$REPO_URL" --token "$RUNNER_TOKEN"
sudo ./svc.sh install
sudo ./svc.sh start
./svc.sh statusيجب أن يعرض svc.sh status الخدمة على أنّها نشطة، وأن يعرض أسطر السجل الأخيرة. يفتح runner اتصال HTTPS صادراً إلى GitHub ويطلب المهام، لذلك لا تفتح أي منفذ وارد له. ينشئ svc.sh install وحدة systemd، وهذه هي الخطوة التي يتجاوزها البعض: من دونها يخرج runner عند انتهاء جلسة SSH، وتبقى كل مهمة لاحقة في قائمة الانتظار من دون تفسير. يشرح الإعداد الكامل لـ self-hosted runner على VPS إجراءات التقوية والتنظيف اللازمة لـ runner يعمل لفترة طويلة.
الفائدة أنّ عملية النشر لم تعد تحتاج إلى مفتاح SSH وارد يمكن الوصول إليه من الإنترنت، لأن المهمة تعمل أصلاً على الخادم. كما تبقى ذاكرة التخزين المؤقت للبناء جاهزة بين عمليات التشغيل، ولا يوجد عداد دقائق يحتسب الاستخدام.
هناك تحذير لا يجوز تجاهله. توصي وثائق GitHub نفسها باستخدام self-hosted runners للمستودعات الخاصة فقط، لأن تفرعات المستودع العام يمكنها تشغيل تعليمات برمجية خطرة على runner لديك عبر فتح pull request. ينفّذ runner كل ما يحدده ملف workflow في ذلك الفرع. في مستودع خاص تتحكم في الجهات التي يمكنها الدفع إليه، يكون الخطر محدوداً. أما في مستودع عام، فتعامل مع أي self-hosted runner على أنّه جهاز يستطيع أشخاص مجهولون تشغيل تعليمات برمجية عليه.
هل تحتاج إلى GitHub أصلاً؟
لا. Git هو المعيار، وGitHub وسيلة ميسّرة. Forgejo وGitea منصتا forge مستضافتان ذاتياً؛ والـforge هو مضيف Git مرفق به نظام للمشكلات وطلبات الدمج. يُوزَّع كلاهما في ملف Go ثنائي واحد، ويعمل كلاهما على VPS صغير. وForgejo هو fork من Gitea أُنشئ في 2022، ويشغّل الآن Codeberg. نقل المستودع يتم بأمر واحد، لأن بروتوكول الاتصال متطابق.
git remote -v
git remote set-url origin git@git.example.com:you/vps-deploy.git
git push origin mainينتقل كل commit، لأن كل clone يحتوي مسبقاً على السجل الكامل. أما ما لا ينتقل فهو الطبقة التي بناها GitHub فوق Git: المشكلات وسلاسل طلبات الدمج. ولا تنتقل CI أيضاً. لدى Forgejo تطبيق Actions خاص به يقرأ YAML مشابهاً من .forgejo/workflows/، وتوضح وثائقه حدود ذلك مباشرةً، إذ تذكر أن GitHub Actions وForgejo Actions ليسا متماثلين، وأن بعض الأمور قد لا تعمل فوراً. ويحتاج Forgejo أيضاً إلى runner خاص به. خطط لهذه الخطوة على أنها عملية نقل، لا نسخ.
السبب الواقعي لبقاء معظم المشاريع هو المساهمون. يجب أن يكون الكود العام في مكان يملك الناس حسابات فيه مسبقاً. أما نصوص النشر الخاصة بك فلا تحتاج إلى ذلك. هذان قراران منفصلان، ويحق لك اتخاذ قرار مختلف لكل منهما.
ما الذي يتعطل أولاً، وماذا يعني الخطأ
تم رفض الدفع. يظهر لك ما يلي:
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'github.com:yourname/vps-deploy.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.تم دفع شيء ما منذ آخر عملية سحب، وغالباً ما يكون تعديلاً أجريته في محرر الويب. شغّل git pull --rebase لإعادة تطبيق التزاماتك فوق التزاماتهم، ثم ادفع مرة أخرى. تجنّب git push --force على فرع مشترك، لأنه يزيل الالتزامات الأخرى من ذلك الفرع على الخادم.
fatal: refusing to merge unrelated histories. شغّلت git init محلياً، وسمحت أيضاً لـGitHub بإنشاء المستودع مع ملف README. لا يشترك السجلان في أي التزام، لذلك لن يخمّن Git الإجراء الصحيح. الحل الأنظف هو استنساخ نسخة GitHub إلى مجلد جديد، ثم نقل ملفاتك إليها.
error: src refspec main does not match any. الفرع الذي حددته غير موجود هنا. عادةً لا يحتوي المستودع على أي التزامات بعد، أو يكون اسم فرعك master. يحسم git branch --show-current الأمر.
وصل سر إلى أحد الالتزامات. غيّر بيانات الاعتماد فوراً. تعامل معها على أنها عامة منذ لحظة دفعها، لأن النسخ المتفرعة والمرايا والعروض المخزنة مؤقتاً تحتوي على نسخ لا تملك طريقة لحذفها.
FAQ
هل GitHub هو نفسه Git؟
لا. Git هو برنامج للتحكم في الإصدارات تثبّته على جهاز، ويعمل من دون شبكة ومن دون حساب. أما GitHub فهو خدمة تجارية مستضافة تخزّن مستودعات Git وتضيف إليها واجهة ويب، وقضايا، وطلبات دمج، وCI. أُصدر Git في 2005، وأُطلق GitHub في 2008 اعتماداً عليه. يمكنك استخدام Git إلى الأبد من دون GitHub. تعتمد كل ميزة في GitHub على Git في الأساس.
هل أحتاج إلى حساب GitHub لاستخدام Git على VPS الخاص بي؟
لا. تعمل git init وgit commit وgit log على خادم لا يحتوي على remote مُعدّ على الإطلاق، وهذا يكفي لتتبّع التغييرات في ملفات /etc أو في scripts النشر. يصبح الحساب مفيداً عندما تريد نسخة من السجل تبقى بعد فقدان الخادم، أو عندما تريد تمكين جهاز ثانٍ من استنساخه. وتوفّر منصات الاستضافة الذاتية مثل Forgejo وGitea الحاجة نفسها على أجهزة تملكها، كما يعمل remote عادي عبر SSH يشير إلى bare repository على جهاز آخر من دون أي برنامج forge.
ما هو طلب الدمج؟
طلب الدمج هو طلب لدمج فرع في فرع آخر، مع إرفاق صفحة للنقاش. تدفع فرعاً، ثم تفتح PR مقابل main، ويعرض المضيف التغيير commit تلو الآخر، بحيث يستطيع المراجعون التعليق على أسطر فردية، وتستطيع الفحوصات الآلية الإبلاغ عن النجاح أو الفشل. هذه ميزة في GitHub وليست ميزة في Git، لذلك لا يحتوي Git نفسه على أمر لها. وتنفّذ المضيفات الأخرى الفكرة نفسها، وتسمّيها أحياناً merge request.
هل ينبغي أن أشغّل runner الخاص بـGitHub Actions على VPS الخاص بي؟
بالنسبة إلى مستودع خاص، غالباً نعم. تعمل المهمة على عتاد تدفع تكلفته مسبقاً، ولا تُحتسب الدقائق، وتبقى build cache جاهزة، كما أن النشر لا يحتاج بعد ذلك إلى تعريض SSH key واردة للإنترنت، لأن runner يتصل بـGitHub اتصالاً صادراً ويطلب المهام. أما بالنسبة إلى مستودع عام، فينصح GitHub بعدم فعل ذلك: إذ يستطيع أي شخص إنشاء fork لمستودعك وفتح pull request يشغّل workflow شفرته على جهازك.
هل يمكنني نقل مستودعاتي خارج GitHub لاحقاً؟
نعم، بالنسبة إلى الشفرة، وبسهولة. تحتوي كل نسخة clone على السجل الكامل، لذلك ينقل git remote set-url origin <new url> ثم push كل ما يتضمنه commit. أما ما يبقى في GitHub فهو الطبقة التي يملكها: إذ تُخزَّن القضايا، ونقاشات طلبات الدمج، وسجل Actions في قاعدة بياناته، لا في مجلد .git لديك. تستطيع أدوات الترحيل نسخ القضايا عبر API، وعادةً تحتاج ملفات workflow إلى تعديل لتعمل مع CI الخاص بالمضيف الجديد. تذكّر ذلك عند توثيق المشروع، فالأفضل وضع التوثيق الفعلي في المستودع بدلاً من وضعه في سلاسل القضايا.