Git: آلة الزمن للكود
💡 دليل التعلم: هذا الفصل مكتوب خصيصاً لمن لم يستخدموا Git أبداً. لن نبدأ بجعلك تحفظ الأوامر، بل سنفهم أولاً "ما المشكلة التي يساعدك Git في حلها؟"، ثم نربط الأوامر والمفاهيم خطوة بخطوة. بعد الانتهاء، يجب أن تكون قادراً بشكل مستقل على: عمل commit محلي، إنشاء فروع، والدفع إلى GitHub.
0. سؤال أولاً: هل عشت هذه الكوابيس؟
السيناريو الأول: جحيم الإصدارات
تكتب مقالاً أو كوداً، وتكتشف في منتصف الطريق أنك أخطأت. تريد العودة لنسخة من ثلاثة أيام — لكنك لا تجدها.
مشروع_v1.zip
مشروع_v2_معدّل.zip
مشروع_v3_النسخة_النهائية.zip
مشروع_v3_النسخة_النهائية_فعلاً_نهائية.zip
مشروع_v3_النهائية_لن_أغيرها_أبداً.zipكلما حفظت نسخة جديدة، يصبح القرص أكثر فوضى، ولا تتذكر ما الذي تغير في كل نسخة.
السيناريو الثاني: كابوس التعاون
أنت وزميلك تعدلان نفس الملف في نفس الوقت:
- أنت غيّرت السطر 10، أضفت وظيفة تسجيل الدخول
- زميلك غيّر السطر 10، أصلح خطأً
- ترسلان الكود عبر البريد الإلكتروني، وعند الدمج يُكتب فوق تغييرات أحدكما
- لا أحد يعرف أي جزء من الكود هو الصحيح
السيناريو الثالث: بلا "حبوب ندم"
تنشر كوداً جديداً في بيئة الإنتاج، يظهر خطأ. تريد التراجع عاجلاً للنسخة المستقرة السابقة — لكنك لا تعرف كيف، ولا يمكنك سوى البحث بشكل محموم عن نسخة احتياطية.
وُلد Git لحل هذه المشاكل الثلاثة بالتحديد.
Git هو نظام تحكم بالإصدارات (Version Control System). جوهره هو: تسجيل كل عملية "حفظ" تقوم بها، مشكّلاً خطاً زمنياً كاملاً للتاريخ، يتيح لك العودة لأي نقطة في أي وقت.
دون مبالغة، Git هو أحد أهم أدوات تطوير البرمجيات الحديثة. كل الشركات تقريباً وكل مشاريع المصادر المفتوحة تستخدمه.
1. هل Git و GitHub شيء واحد؟
كثير من المبتدئين يخلطون بين المفهومين. لنوضح:
| Git | GitHub | |
|---|---|---|
| ما هو | أداة تحكم بالإصدارات تعمل على حاسوبك | موقع يخزن مستودعات Git (في السحابة) |
| أين | حاسوبك المحلي | على الإنترنت |
| هل يمكن استخدامه بشكل مستقل؟ | ✅ نعم، يدير التاريخ المحلي فقط | ❌ يحتاج للاستخدام مع Git |
| تشبيه | دفتر يومياتك المحلي | تخزين سحابي لليوميات |
باختصار: Git هو الأداة، GitHub هو خدمة الاستضافة. مثلما Word هو الأداة وOneDrive هو السحابة، يعملان معاً لكنهما ليسا نفس الشيء.
إلى جانب GitHub، هناك خدمات مشابهة مثل GitLab وGitee وغيرها.
2. المفهوم الأساسي: المناطق الثلاث
هذا هو التصميم الأهم في Git. فهم هذه المناطق الثلاث يعني فهم روح Git.
Git يقسم حالة ملفاتك إلى ثلاث طبقات:
دليل العمل (Working Directory) هو مجلدك العادي، كل الملفات التي تراها وتحررها موجودة هنا. عدّل كما تشاء؛ Git سيلاحظ ما تغير لكنه لن يسجل شيئاً.
منطقة الإعداد (Staging Area / Index) هي محطة عبور "ما قبل الالتزام". يمكنك "وضع" الملفات من دليل العمل التي تريد حفظها في منطقة الإعداد، كأن تضع طروداً في صندوق شحن — لم تُرسل بعد، لكنك اخترت ما تريد إرساله.
المستودع (Repository) هو أرشيف التاريخ الدائم، مخفي في مجلد .git. كلما نفّذت git commit، يُختم محتوى منطقة الإعداد في المستودع، مشكّلاً سجلاً تاريخياً لا يمكن التلاعب به.
👇 جرّب: انقر على أزرار الأوامر بالتسلسل ولاحظ كيف تتدفق الملفات بين المناطق الثلاث.
files you are editing
login.jsunstagedstyle.cssunstageddebug.logunstagedgit addfiles prepared for this commit
git commitversions saved permanently
9f3e1b2init: initialize projectHEADلماذا نهج "خطوتين" (add + commit)؟
كثير من المبتدئين يسألون: لماذا لا يمكن الحفظ بنقرة واحدة، بل يجب add أولاً ثم commit؟
لأنه في التطوير الفعلي، غالباً لا تريد تأكيد كل التغييرات دفعة واحدة.
مثال: عدّلت اليوم 5 ملفات:
login.js: أكملت وظيفة تسجيل الدخول (تريد التأكيد)style.css: عدّلت أنماط صفحة الدخول (تريد التأكيد)debug.log: مخرجات تصحيح مؤقتة (لا تريد التأكيد)experiment.js: ميزة جديدة قيد التجربة، لم تكتمل (لا تريد التأكيد)todo.txt: ملاحظاتك الشخصية (لا تريد التأكيد)
بدون منطقة الإعداد، إما تؤكد كل الملفات الخمسة (سجل فوضوي) أو لا تؤكد أي شيء.
مع منطقة الإعداد، يمكنك التحكم بدقة: git add login.js style.css، تضع هذين الملفين فقط في الصندوق، ثم commit. هذا الالتزام سيسجل بوضوح "اكتملت وظيفة تسجيل الدخول".
3. الاستخدام الأول لـ Git: التهيئة وسير العمل الأساسي
3.1 التثبيت والتهيئة
بعد تثبيت Git (macOS يتضمنه، Windows حمّله من git-scm.com)، افتح الطرفية وانتقل لمجلد مشروعك:
# تهيئة مستودع Git في المجلد الحالي
git init
# سينشئ Git مجلداً مخفياً .git، كل التاريخ مخزن فيه
# المخرج: Initialized empty Git repository in .../your-project/.git/في المرة الأولى تحتاج لإخبار Git من أنت (هذه المعلومات تُرفق بكل التزام):
git config --global user.name "اسمك"
git config --global user.email "بريدك@مثال.com"3.2 سير العمل اليومي: الحفظ في ثلاث خطوات
بعد التهيئة، 90% من عمليات التطوير اليومية هي تكرار هذه الخطوات الثلاث:
الخطوة 1: عرض الحالة
git statusهذا هو الأمر الأكثر استخداماً على الإطلاق. يخبرك:
- على أي فرع أنت
- أي ملفات تم تعديلها (أحمر = غير مُجهز)
- أي ملفات في منطقة الإعداد (أخضر = مُجهزة، بانتظار الالتزام)
الخطوة 2: وضع الملفات في منطقة الإعداد
# إضافة ملف واحد
git add login.js
# إضافة عدة ملفات
git add login.js style.css
# إضافة كل الملفات المعدّلة في المجلد الحالي (النقطة تعني "الكل")
git add .⚠️ خطأ شائع للمبتدئين:
git add .مريح جداً لكنه يضيف كل التعديلات بما فيها ملفات مؤقتة لا تريد تأكيدها. اعتد على الإضافة الدقيقة، أو استخدم.gitignoreلاستبعاد ما لا تريد تتبعه (سيُشرح لاحقاً).
الخطوة 3: الالتزام مع وصف
git commit -m "feat: إضافة وظيفة تسجيل دخول المستخدم"المحتوى بين علامتي التنصيص بعد -m يُسمى رسالة الالتزام (commit message). مكتوبة لنفسك المستقبلي وزملائك؛ يجب أن تكون ذات معنى.
3.3 كيف تكتب رسالة التزام احترافية؟
# ❌ كتابة غير مفيدة — لا تعرف ماذا تم
git commit -m "update"
git commit -m "fix"
git commit -m "غيّرت بعض الأشياء"
# ✅ كتابة جيدة: النوع + نقطتان + وصف بجملة واحدة
git commit -m "feat: إضافة وظيفة تسجيل دخول المستخدم"
git commit -m "fix: إصلاح الشاشة البيضاء في iOS Safari"
git commit -m "docs: تحديث تعليمات النشر في README"
git commit -m "refactor: فصل UserService إلى وحدة مستقلة"
git commit -m "style: توحيد مسافة البادئة إلى مسافتين"معاني البادئات الشائعة:
| البادئة | المعنى |
|---|---|
feat: | ميزة جديدة (feature) |
fix: | إصلاح خطأ |
docs: | تغييرات في التوثيق |
style: | تعديلات التنسيق (لا تؤثر على الوظائف) |
refactor: | إعادة هيكلة الكود (الوظيفة كما هي، البنية محسّنة) |
chore: | متعلق بالبناء، الأدوات، التبعيات |
test: | متعلق بالاختبارات |
اكتسب هذه العادة، وبعد أشهر عند مراجعة التاريخ، ستعرف بلمحة ماذا فعل كل التزام. هذا مهم جداً في العمل الجماعي.
3.4 عرض السجل التاريخي
# تنسيق مفصل (معلومات كاملة لكل التزام)
git log
# تنسيق موجز (سطر واحد لكل التزام، موصى به للاستخدام اليومي)
git log --oneline
# مثال على المخرجات:
# a1b2c3d (HEAD -> main) feat: إضافة وظيفة تسجيل دخول المستخدم
# 9f3e1b2 init: تهيئة المشروع4. الأكوان المتوازية: الفروع (Branch)
الفروع هي أقوى وظيفة في Git، وأكثر ما يربك المبتدئين. لكن بمجرد فهمها، ستجد التصميم أنيقاً جداً.
4.1 ما هو الفرع؟ افهمه كـ "أكوان متوازية"
تخيل أنك تلعب لعبة تقمص أدوار بها خيار حاسم:
- الخيار أ: تحدي الزعيم الكبير (تطوير ميزة جديدة)
- الخيار ب: الحفاظ على الاستقرار الحالي (الخط الرئيسي لا يتغير)
إذا اخترت أ مباشرة على الحفظ الرئيسي وخسرت، كل تقدم اللعبة يضيع.
لكن إذا نسخت الحفظ وتحديت الزعيم في النسخة:
- فزت؟ ادمج نتائج النسخة في الحفظ الرئيسي
- خسرت؟ الحفظ الرئيسي لم يتأثر إطلاقاً، احذف النسخة وحاول مجدداً
فروع Git هي بالضبط آلية "نسخ الحفظ" هذه.
في Git، الفرع main (أو master) هو "حفظك الرئيسي"، ويجب أن يبقى مستقراً دائماً. عندما تريد تطوير ميزة جديدة، تنشئ فرعاً جديداً من main، تطوّر وتختبر هناك، وعند الانتهاء تدمجه مع main.
4.2 عرض مرئي للفروع
👇 جرّب: انقر على أزرار الأوامر بالتسلسل ولاحظ كيف يتفرع مخطط الفروع ويمتد وينتهي بالدمج. ركز على موضع علامة HEAD — يشير دائماً إلى "أين أنت الآن".
4.3 عمليات الفروع بالتفصيل
إنشاء فرع جديد والانتقال إليه:
# الطريقة 1: أنشئ أولاً، ثم انتقل (خطوتان)
git branch feature-login # إنشاء فرع
git checkout feature-login # الانتقال إليه
# الطريقة 2: بخطوة واحدة (موصى بها)
git checkout -b feature-login
# المخرج: Switched to a new branch 'feature-login'بعد إنشاء الفرع، سيظهر محث سطر الأوامر اسم الفرع الحالي، مثلاً:
user@mac ~/project (feature-login) $عرض جميع الفروع:
git branch
# المخرج (* يشير للفرع الحالي):
# * feature-login
# mainالتطوير الطبيعي على الفرع:
# على فرع feature-login، تعديل الكود، add، commit — تماماً كالمعتاد
git add login.js
git commit -m "feat: إضافة بنية HTML لنموذج تسجيل الدخول"
git add login.js api.js
git commit -m "feat: إكمال ربط واجهة تسجيل الدخول"هذه الالتزامات موجودة فقط على فرع feature-login؛ فرع main لا يعرف شيئاً عما فعلته.
العودة للفرع الرئيسي والدمج:
# العودة لـ main
git checkout main
# دمج كل تغييرات feature-login
git merge feature-login
# بعد الدمج، يمكنك حذف الفرع (اختياري)
git branch -d feature-login4.4 متى يجب فتح فرع؟
| السيناريو | التوصية | السبب |
|---|---|---|
| تطوير ميزة جديدة | ✅ افتح فرعاً | لا يؤثر على الخط الرئيسي قبل الإكمال؛ يمكنك التخلي عنه في أي وقت |
| إصلاح خطأ عاجل في الإنتاج | ✅ افتح hotfix-xxx من main | يُدمج مباشرة بعد الإصلاح دون إدخال ميزات غير مكتملة |
| التطوير المتوازي مع الزملاء | ✅ كل واحد بفرع خاص | بدون تداخل؛ دمج موحد عبر Pull Request عند الانتهاء |
| تصحيح خطأ مطبعي فقط | ❌ مباشرة على main | خطر منخفض جداً، لا حاجة لفرع إضافي |
4.5 استراتيجية الفروع الشائعة في الفرق
في المشاريع الحقيقية، يتفق الفريق عادة على تسمية الفروع واستخداماتها:
| اسم الفرع | الاستخدام | الخصائص |
|---|---|---|
main / master | الكود المستقر للإنتاج | فقط الكود الذي اجتاز الاختبارات يدخل؛ لا يمكن الدفع مباشرة |
dev / develop | فرع التكامل اليومي | كل فروع الميزات تُدمج هنا أولاً؛ بعد اجتياز الاختبارات يصعد لـ main |
feature/xxx | تطوير ميزات محددة | مثل feature/user-login؛ يُدمج مع dev عند الإكمال |
hotfix/xxx | إصلاحات عاجلة | يُنشأ من main؛ بعد الإصلاح يُدمج مباشرة مع main و dev |
5. التعاون مع الفريق: المستودع البعيد
كل ما تعلمته حتى الآن هو عمليات محلية في Git — كل التاريخ على حاسوبك. لمشاركة الكود مع زملائك، تحتاج مستودعاً بعيداً، مثل GitHub أو GitLab.
5.1 كيف يعمل المستودع البعيد
المستودع البعيد يعمل كـ "حفظ عام" مشترك للفريق:
- كل شخص يكتب كوداً ويقوم بـ commit محلياً
- عند الانتهاء، يقوم بـ
push(رفع) للمستودع البعيد - الزملاء يقومون بـ
pull(تنزيل) أحدث محتوى من المستودع البعيد لأجهزتهم - هكذا يبقى كود الجميع متزامناً
👇 جرّب: انقر على الأوامر بالتسلسل لاختبار المسار الكامل من ربط المستودع البعيد والدفع وسحب تحديثات الزملاء.
9f3e1b2init: initialize projectc4d8a31feat: homepage layout5.2 أول دفع لمشروع إلى GitHub
الخطوة 1: أنشئ مستودعاً جديداً على GitHub (انقر على + في الزاوية العلوية اليمنى ← New repository)، دون تحديد خيارات التهيئة.
الخطوة 2: عد للطرفية المحلية واربط المستودع البعيد:
# ربط المستودع المحلي مع GitHub
# "origin" هو اسم مستعار للمستودع البعيد، اسم متفق عليه (يمكن تغييره لكن لا داعي)
git remote add origin https://github.com/اسم-المستخدم/اسم-المستودع.git
# تأكيد نجاح الربط
git remote -v
# المخرج:
# origin https://github.com/اسم-المستخدم/اسم-المستودع.git (fetch)
# origin https://github.com/اسم-المستخدم/اسم-المستودع.git (push)الخطوة 3: ارفع المحتوى المحلي للبعيد:
# أول دفع؛ -u تعني "في ما بعد، git push سيرفع افتراضياً إلى فرع main في origin"
git push -u origin main
# بعد ذلك كل دفع يحتاج فقط:
git push5.3 أوامر التعاون اليومية
الدفع (أجريت تغييرات وتريد أن يراها زملاؤك):
git pushالسحب (زملاؤك أجروا تغييرات وتريد المزامنة):
git pullgit pull هو في الواقع مزيج من أمرين:
git fetch: ينزّل أحدث الالتزامات من المستودع البعيدgit merge: يدمج المحتوى المنزّل مع فرعك الحالي
أول مرة تحصل على مشروع شخص آخر من GitHub:
# انسخ المستودع البعيد بالكامل محلياً (مرة واحدة فقط)
git clone https://github.com/شخص/مشروع.git
# clone يُنشئ تلقائياً الارتباط البعيد؛ بعد ذلك استخدم push/pull مباشرة5.4 اتجاه الدفع والسحب
حاسوبك (المستودع المحلي) ←→ GitHub (المستودع البعيد)
git push: محلي ← بعيد (أجريت تغييرات، ترفعها لزملائك)
git pull: بعيد ← محلي (زملاؤك أجروا تغييرات، تنزلها)
git clone: بعيد ← محلي (أول نسخة كاملة من المستودع)أفضل ممارسة: قم بـ
git pullكل يوم قبل بدء العمل للحصول على أحدث كود؛ وgit pushعند الانتهاء أو إكمال ميزة، للنسخ الاحتياطي وإطلاع زملائك على تقدمك.
6. متقدم: معالجة التعارضات
التعارضات أمر لا مفر منه في التعاون، لكنها ليست مرعبة أيضاً.
6.1 كيف تحدث التعارضات؟
عندما أنت وزميلك تعدلان نفس السطر من نفس الملف، عند الدمج لا يعرف Git أي نسخة يستخدم، فينشأ تعارض.
مثال:
- في
login.jsالسطر 5 كتبت:const timeout = 3000 - زميلك كتب في نفس السطر:
const timeout = 5000 - عند
git pullأوgit merge، يكتشف Git التناقض و"يتوقف" قائلاً: لا أعرف أيهما أستخدم، فلتقرر أنت.
6.2 كيف يبدو الملف المتعارض؟
يدرج Git علامات خاصة في مناطق التعارض:
function login() {
const url = '/api/login'
<<<<<<< HEAD
const timeout = 3000 // نسختك
=======
const timeout = 5000 // نسخة زميلك
>>>>>>> feature/update-timeout
return fetch(url, { timeout })
}- بين
<<<<<<< HEADو=======: محتوى فرعك الحالي - بين
=======و>>>>>>> xxx: المحتوى المُدمج
6.3 كيف تحل تعارضاً؟
الخطوة 1: افتح الملف المتعارض وابحث عن كل علامات <<<<<<< (عادة VS Code وغيرها من المحررات تُبرزها تلقائياً)
الخطوة 2: قرر أي جزء من الكود ستحتفظ به، حرر الملف يدوياً، واحذف كل العلامات (<<<<<<<, =======, >>>>>>>).
مثلاً إذا قررت استخدام 5000 (نسخة الزميل):
function login() {
const url = '/api/login'
const timeout = 5000 // اعتماد تعديل الزميل
return fetch(url, { timeout })
}الخطوة 3: أعد الالتزام
# تعليم التعارض كمحلول
git add login.js
# إكمال التزام الدمج (سيُنشئ Git رسالة الدمج تلقائياً)
git commit6.4 عادات جيدة لتقليل التعارضات
- اسحب بشكل متكرر: زامن أحدث كود قبل بدء العمل، لتقليل "التخلف كثيراً"
- التزامات صغيرة ومتكررة: لا تكتب كوداً لأسبوع ثم تلتزم دفعة واحدة؛ الالتزامات المتكررة تُسهّل اكتشاف التعارضات وحلها
- العزل بالفروع: ميزات مختلفة في فروع مختلفة، لتقليل التنافس على نفس السطر
- التواصل: قبل تعديل ملفات مشتركة (مثل
config.js)، أخبر زملائك
7. مرجع سريع للأوامر
Save this table and check it whenever a Git command slips your mind:
8. تطبيق عملي: المسار الكامل للانضمام لمشروع فريق
هذا هو مسار العمليات القياسي عند انضمامك لفريق أو مشروع جديد؛ يمكنك نسخه مباشرة:
# ① اليوم الأول: استنساخ المشروع محلياً (مرة واحدة فقط)
git clone https://github.com/team/project.git
cd project
# ② كل يوم عند البدء: اسحب أحدث كود أولاً
git pull origin main
# ③ أنشئ فرع ميزتك (لا تعدّل main مباشرة)
git checkout -b feature/user-profile
# ④ التطوير الطبيعي... كتابة الكود...
# ⑤ عند إكمال ميزة صغيرة، التزم فوراً (لا تتراكم)
git add src/UserProfile.vue
git commit -m "feat: إكمال وظيفة رفع صورة المستخدم"
git add src/UserProfile.vue src/api/user.js
git commit -m "feat: إكمال واجهة تعديل بيانات المستخدم"
# ⑥ ارفع فرعك للبعيد ليتمكن زملاؤك من رؤيته
git push origin feature/user-profile
# ⑦ أنشئ طلب سحب (PR) على GitHub، لطلب الدمج مع main
# (هذه الخطوة على واجهة GitHub)
# ⑧ انتظر مراجعة الكود من زملائك، عدّل حسب الملاحظات، وواصل commit + push
# ⑨ بعد دمج PR، عد لـ main، حدّث محلياً، احذف فرع الميزة
git checkout main
git pull
git branch -d feature/user-profile9. .gitignore: أي ملفات لا يجب تتبعها؟
هناك ملفات لا تريد تأكيدها في مستودع Git، مثل:
node_modules/: حزم التبعية، حجمها كبير جداً، يمكن إعادة إنشائها بـnpm install.env: ملف متغيرات البيئة، قد يحتوي كلمات مرور قواعد البيانات ومفاتيح API، لا يجب رفعه لمستودع عام أبداً*.log: ملفات السجل.DS_Store: ملف مخفي يُنشئه macOS تلقائياًdist/,build/: مخرجات البناء، يمكن إعادة بنائها
أنشئ ملف .gitignore في جذر المشروع بقواعد الملفات التي لا تريد تتبعها:
# التبعيات
node_modules/
# متغيرات البيئة (مهم! كلمات المرور لا يجب رفعها)
.env
.env.local
# مخرجات البناء
dist/
build/
# ملفات النظام
.DS_Store
Thumbs.db
# السجلات
*.logيحتوي GitHub على قوالب .gitignore لمختلف اللغات والأُطر: github.com/github/gitignore
جدول مرجعي للمصطلحات
| المصطلح | الإنجليزية | الشرح |
|---|---|---|
| المستودع | Repository (Repo) | قاعدة بيانات تخزن كل تاريخ إصدارات المشروع، في مجلد .git |
| الالتزام | Commit | تسجيل كامل لإصدار، كنقطة حفظ في لعبة، مع وصف وختم زمني |
| الفرع | Branch | خط تطوير مستقل، كخط زمني متوازي، لا يؤثر على الآخرين |
| الدمج | Merge | دمج تغييرات فرع في فرع آخر |
| التعارض | Conflict | نفس السطر عُدّل من عدة أشخاص، Git لا يعرف أي نسخة يستخدم، يتطلب حلاً يدوياً |
| الإعداد | Stage / Index | وضع التعديلات في قائمة "جاهزة للالتزام" |
| البعيد | Remote | نسخة المستودع في السحابة (GitHub / GitLab / Gitee) |
| الاستنساخ | Clone | نسخ المستودع البعيد بالكامل محلياً |
| الدفع | Push | رفع الالتزامات المحلية للمستودع البعيد |
| السحب | Pull | تنزيل ودمج أحدث محتوى من البعيد محلياً |
| HEAD | HEAD | مؤشر للفرع/الالتزام الحالي، يشير إلى "أين أنت الآن" |
| origin | origin | الاسم المستعار الافتراضي للمستودع البعيد (اسم متفق عليه) |
| stash | Stash | حفظ مؤقت لتغييرات غير ملتزم بها؛ مفيد عند تبديل المهام |
| PR / MR | Pull Request / Merge Request | طلب دمج فرعك في الفرع الرئيسي، يتطلب عادةً مراجعة من الزملاء |