تعلم Git وGitHub
Git برنامج على حاسوبك أنت، يحفظ متى أمرته لقطة مؤرخة لحالة مشروعك مع ملاحظة، ويتيح لك لاحقا العودة إلى أي من تلك اللقطات. أما GitHub فأحد الأماكن التي يمكنك أن تضع فيها نسخة من هذا التاريخ؛ وGit نفسه يعمل كاملا بلا إنترنت وبلا أي حساب.
- الدرس 9 من 14
- مبتدئ
- مجاني، دون تسجيل
حياة تغيير واحد، من التحرير إلى التاريخ
-
1
تحرير الملف
لم يفعل Git شيئا بعد. التغيير على القرص وليس في التاريخ.
-
2
git add
تختار ما يدخل في هذه اللقطة. وهذه الخطوة هي التي تُنسى عادة.
-
3
git commit
تُسجَّل اللقطة بتاريخ واسم ورسالة. ومن هنا تصير قابلة للاسترجاع.
-
4
git push
تحط نسخة من التاريخ على مضيف أيضا. وهي الخطوة الوحيدة التي تحتاج شبكة.
-
5
git log
تعود كل لقطة بتاريخها ورسالتها. وهنا تعرف كم كانت الرسالة الجيدة تساوي.
هذا الترتيب لشخص واحد على فرع واحد. والعمل الجماعي يضيف pull وmerge وحل التعارض، وهذا الدرس لا يغطيها.
آخر مراجعة: تُراجع الحقائق وأسماء الأدوات في هذا الدرس مقابل مصادرها في هذا التاريخ.
ما المشكلة التي يحلها Git ولا يحلها نسخ المجلد؟
رأى الجميع الطريقة السابقة على Git: site وsite-final وsite-final-2، وذلك المجلد الذي لا يجرؤ أحد على حذفه. والعيب فيها ليس قبحها؛ بل أن أيا من تلك المجلدات لا يقول لماذا صُنع ولا أي الملفات تغيرت معا.
Git نظام للتحكم بالإصدارات: فبدلا من الاحتفاظ بعدة نسخ كاملة، يسجل حالة المشروع عند نقاط تختارها أنت. وكل نقطة هي commit تحمل ثلاثة أشياء لا يملكها المجلد المنسوخ أبدا: تاريخا وساعة دقيقين، واسم من سجلها، ورسالة تقول لماذا جرى هذا التغيير.
وفي الشيء الثالث تكمن قيمة Git الحقيقية. فبعد ستة أشهر، حين تصل إلى سطر لا تفهم معناه، لن يكون سؤالك من أين جاء هذا السطر؛ بل لماذا فعل أحدهم ذلك. وGit يجيب عن هذا السؤال بالذات، شرط أن تكون كتبت الرسائل بجدية. فتاريخ مليء بـ«تعديلات» و«إصلاح» عديم الفائدة تماما كمجلد final-2.
وفرق عملي ينفعك قبل غيره: يتيح لك Git أن ترى أي الأسطر بالضبط اختلفت بين نقطتين. وحين يتعطل اليوم موقع كان يعمل أمس، فتلك ليست ميزة رفاهية بل الطريق الوحيد لإيجاد السبب في دقائق بدل ساعات.
Git وGitHub ليسا شيئا واحدا
Git برنامج يُثبَّت على حاسوبك أنت وعمله حفظ التاريخ. أما GitHub فشركة تستضيف تلك التواريخ على خوادمها وبنت حولها أشياء أخرى: صفحات الملف الشخصي، وتتبع الأعطال، ومراجعة الشفرة وغيرها. أحدهما أداة والآخر خدمة؛ تقريبا كنسبة برنامج الكتابة إلى البريد.
ولهذا التمييز خاصية تضيع عادة في الدروس: Git موزَّع، أي أن حاسوبك يحمل نسخة كاملة من التاريخ لا مؤشرا إلى خادم. تستطيع أن تسجل commit طوال اليوم وتقرأ التاريخ وتعود إلى الوراء دون أن تتصل بالإنترنت مرة واحدة. وpush لا يفعل سوى وضع نسخة من التاريخ نفسه في مكان آخر أيضا.
فإن صار ذلك المضيف بعيد المنال غدا، لا يصير المستودع على جهازك ناقصا، وتستطيع إرساله إلى أي مكان آخر: GitLab أو خادم خاص أو حتى قرص خارجي. والذي يضيع مع المضيف هو الأعطال المسجلة وطلبات الدمج والنقاشات تحتها، لأنها ليست داخل Git أصلا بل من صنع تلك الشركة.
وجملة عملية للقارئ في إيران: إمكانية الوصول إلى خدمات الاستضافة الأجنبية شيء تختبره أنت في يومه، ولا نكتب هنا ادعاء اليوم عنه. والقرار الصحيح مستقل عن ذلك على أي حال: احفظ التاريخ في مكان لا يوقف عملك إن اختفت خدمة واحدة. وهذا يوافق طبيعة Git ولا يعتمد على أي خدمة.
أين يعيش التاريخ؟ على الحاسوبين معا
حاسوبك
- نسخة كاملة من التاريخ لا مؤشر
- الـcommit يعمل بلا إنترنت
حاسوب زميلك
- يملك هو أيضا التاريخ الكامل نفسه
- يعمل كل منكما مستقلا ثم تتزامنان
المضيف مجرد نسخة لا مالك للتاريخ
GitHub أو أي مضيف آخر
- نسخة مشتركة في الوسط للتزامن
- الأعطال ومراجعة الشفرة والملف الشخصي من إضافاته هو
إن صار المضيف بعيد المنال، فتاريخ الشفرة سليم ويمكن دفعه إلى أي مكان آخر. والذي يذهب مع المضيف هو الأعطال ومراجعات الشفرة، لأنها ليست داخل Git.
الأوامر الأربعة الأولى، ولماذا يوجد add أصلا
تضع مشروعا تحت إشراف Git بـgit init. وهذا الأمر ينشئ مجلدا مخفيا اسمه .git، ومن بعده يصير كل ما يجري في ذلك المجلد قابلا للتسجيل. ولم يُسجَّل شيء بعد؛ فُتح الدفتر فحسب.
git init
git add index.html
git commit -m "first page with contact form"
git push origin mainوالأمر الذي يحير المبتدئين هو add، لأنه يبدو خطوة زائدة. وليس كذلك. فبين ملفاتك والتاريخ طاولة وسيطة تسمى منطقة التجهيز، وadd يعني «ضع هذا على الطاولة، أريده في اللقطة التالية». وهذه الطاولة هي ما يتيح لك أن تسجل في commit واحد ثلاثة ملفات تخص عملا واحدا من بين عشرة غيرتها اليوم.
وهنا تتكون أول عادة محترفة: الـcommit الواحد ينبغي أن يكون عملا واحدا. فإن اضطررت لاستعمال «و» في رسالة الـcommit، فالأرجح أنه ينبغي أن يكون اثنين. وهذه ليست مسألة ذوق؛ بل تدفع ثمنها يوم تريد التراجع عن تغيير واحد وقد اختلط ذلك التغيير في commit مع عملين آخرين.
وpush هو الوحيد من الأربعة الذي يحتاج شبكة. أما الثلاثة الأولى فتعمل كلها على جهازك أنت. واحفظ هذا تصر رسائل خطأ Git ذات معنى: فخطأ الوصول والتحقق يخص push في الغالب دائما، و«لا شيء للتسجيل» يعني في الغالب دائما أنك نسيت add.
أول ما يفسد: ملف ما كان ينبغي أن يُسجَّل
ملف اسمه .gitignore في جذر المشروع يقول لـGit ما الذي يتركه وشأنه. وفيه ثلاث فئات دائما: مجلد الاعتماديات الذي يُعاد تثبيته، والملفات التي تُنتَج عند البناء، وكل ما يحمل كلمة سر أو مفتاحا حقيقيا.
والفئة الثالثة هي حيث يُصاب الناس. فملف الإعدادات وفيه كلمة سر قاعدة البيانات يُسجَّل مرة، ثم ينتبه أحدهم فيزيل كلمة السر من الملف ويسجل commit جديدا. والعمل لم يتم: Git يحفظ التاريخ، وتلك الكلمة ما زالت داخل الـcommit السابق وتُرى بأمر بسيط واحد.
ودليل GitHub نفسه يقول هذا: بعد حادثة كهذه عليك أن تعد ذلك الاعتماد محروقا وتغيره، وإزالة الملف من التاريخ وحدها لا تكفي. والترتيب الصحيح معكوس لما يتوقعه المرء: غيّر كلمة السر أولا، ثم فكر في تنظيف التاريخ.
فالعادة التي تستحق أن تبدأ بها من اليوم الأول هي هذه: اكتب .gitignore قبل أول commit لا بعده. وإن احتاج المشروع نموذج إعدادات، فضع ملفا مثل config.example بقيم فارغة، ليعرف من يأتي بعدك ما المطلوب دون أن تُسجَّل أي قيمة حقيقية في أي مكان.
يُسجَّل
- شفرة المشروع وملفاته النصية
- ملف قفل الاعتماديات ليثبّت الجميع نسخة واحدة
- نموذج إعدادات بقيم فارغة
- ملف gitignore نفسه
لا يُسجَّل أبدا
- ملف إعدادات فيه كلمة سر أو مفتاح حقيقي
- مجلد الاعتماديات الذي يعيد أمر واحد تثبيته
- مخرجات البناء والملفات المولَّدة
- نسخ قاعدة البيانات وملفات رفع المستخدمين
هذا الملف يمنع ما لم يُسجَّل بعد فقط. أما ملف سُجِّل مرة فلا تُزيله من التاريخ إضافته إلى هذه القائمة.
الموقع الذي كُتب عليه هذا الدرس ليس في Git
يُحرَّر rgb.ir على خادم حي وليس له مستودع Git. ونكتب هذا لأن درسا يكتفي بالنصح دون أن يقول أين يقف هو نفسه إنما يقول نصف الحقيقة.
فما الذي حل محل Git؟ المحرر الذي كتبناه للقالب يضع نسخة من الملف جانبا قبل كل حفظ، باسم فيه التاريخ والساعة، ويحتفظ بآخر عشرين نسخة من كل ملف. ثم يحلل الملف الجديد بـtoken_get_all مع الراية TOKEN_PARSE، لأن php -l وproc_open كليهما معطلان على هذا الخادم وطريق فحص النحو المعتاد غير متاح. وإن لم يُحلَّل الملف الجديد، عادت تلك النسخة السابقة تلقائيا كي لا تسقط الصفحة الحية.
وهذا تقريبا الحد الأدنى من تعريف نظام إصدارات، وهو يؤدي عمله جيدا. لكن فرقه عن Git هو بالضبط ما دار حوله هذا الدرس: لا واحدة من تلك النسخ العشرين تقول لماذا حُفظت، ولا شيء يربط ملفين تغيرا معا، وبعد النسخة الحادية والعشرين لا يبقى شيء.
فإن لم يكن مشروعك في Git بعد، فهذا الدرس ليس توبيخا. لكن اعرف الكلفة: غياب Git لا يكلف شيئا البتة يوم يعمل كل شيء، ويحصّل الفاتورة كاملة يوم لا يعمل.
المسار السريع مع الذكاء الاصطناعي
ما يفعله المحترفون مع الذكاء الاصطناعي وGit في ٢٠٢٦ ليس منح النموذج صلاحية تنفيذ الأوامر؛ بل العكس. فأنت تريه التغييرات التي ستُسجَّل، وتطلب قبل الـcommit ثلاثة أشياء: هل خلطت أعمالا غير مترابطة، وهل هنا شيء يشبه كلمة سر، ورسالة commit تقول «لماذا» لا «ماذا». والبند الثاني هو ما يفصل هذه الوصفة عن طلب رسالة commit عادي، وفيه معظم القيمة.
- استعمل <code>git add -p</code> لتختار ما يوضع على الطاولة قطعة قطعة، بدل إضافة المجلد كله. وهذا الأمر وحده يحذف نصف أخطاء هذا العمل قبل وقوعها.
- خذ مخرجات <code>git diff --staged</code> وأرسلها مع الوصفة أدناه. واقرأ جواب البندين الأول والثاني أولا، ثم انتقل إلى الرسالة.
- إن أُدرج شيء يشبه مفتاحا أو كلمة سر، فقف هناك: أزله عن الطاولة بـ<code>git restore --staged</code>، وضع الملف في gitignore، وإن كانت القيمة حقيقية فغيّرها.
- خذ الرسالة من مسودة النموذج لكن أعد كتابتها بنفسك. فالنموذج يقرأ «ما الذي تغير» من الـdiff، أما «لماذا» فتعرفه أنت وحدك وهو ما ينفع بعد ستة أشهر.
وصفة جاهزة للنسخ
هذه مخرجات git diff --staged.
{مخرجات diff}
أعطني ثلاثة أشياء بهذا الترتيب:
١. إن كانت هذه التغييرات تحتوي أكثر من عمل غير مترابط، فقل أي الأسطر تخص أي عمل، واقترح كيف تُقسَّم إلى commits منفصلة.
٢. اذكر كل ما يشبه كلمة سر أو مفتاحا أو رمزا أو عنوانا داخليا أو بيانات عميل حقيقي. وإن لم يكن هناك شيء، فقل ذلك صراحة.
٣. اكتب رسالة commit: سطر أول لا يتجاوز خمسين حرفا بصيغة الأمر، ثم سطر فارغ، ثم سطران إلى أربعة تشرح «لماذا» لا «ماذا».
ولا تكتب أي أمر Git لأنفذه. وإن احتاج الجواب شفرة ليست في هذا الـdiff، فقل أيها ولماذا؛ ولا تخمّن.
قبل أن تثق بالناتج: حدان لا تتجاوزهما هذه الوصفة. الأول أن النموذج لا يرى إلا ذلك الـdiff: فإن كسر تغييرك شيئا في موضع آخر من المشروع، فلا أثر لذلك في هذه المخرجات والطريق الوحيد هو تشغيل البرنامج. والثاني أن إرسال diff يعني إرسال شفرتك إلى شركة أخرى؛ فإن كان المشروع لعميل، فخذ إذنه أولا واقرأ صفحة استعمال البيانات لتلك الخدمة. والسطر الأخير من الوصفة ليس زينة أيضا: أمر Git الذي لا تستطيع شرحه لا يُنفَّذ.
الذكاء الاصطناعي في هذا العمل
موقفنا من Git والذكاء الاصطناعي واضح: أبقِ النموذج في دور قراءة النص وكتابته، لا في دور من يدير مستودعك. فصياغة رسالة commit، وتلخيص diff طويل، وشرح ما فعله commit قديم، ثلاثة أعمال تجيدها النماذج فعلا وتعيد إليك وقتا. أما تنفيذ الأوامر فشأن آخر، وقسم الخطر يقول لماذا.
أدوات تساعد فعلا
- Claude Code يجلس في الطرفية بجوار المستودع، فبدل نسخ الـdiff يدويا يقرؤه هو بنفسه. ولسؤال «ماذا فعل هذا الـcommit» و«لماذا هذا السطر هنا» هو أفضل خيار في هذه القائمة. يُثبَّت مجانا لكنه لا يعمل دون اشتراك كلود أو حساب في كونسول أنثروبيك، وإيران ليست في قائمة الدول المدعومة لدى أنثروبيك.
- Claude للوصفة أعلاه تكفي نافذة محادثة: تلصق الـdiff وتحصل على البنود الثلاثة. وإيران ليست في أي من قائمتي الدول المدعومة لدى أنثروبيك؛ قرأنا ذلك في صفحة أنثروبيك نفسها لا عبر اختبار شبكة.
- Gemini لرسالة الـcommit ولتلخيص diff يكفي نموذج سريع رخيص وهنا موضعه؛ أما لكشف اختلاط عملين غير مترابطين فالنموذج الأقوى يجيب أفضل. وصفحة غوغل نفسها تقول إن تطبيق جيميناي على الويب يعمل في أكثر من ٢٣٠ دولة وإقليما، وإيران ليست في تلك القائمة.
اين ينقلب ضدك
الخطر الأساسي هنا صنف محدد من الأوامر لا الأدوات. فأغلب عمليات Git قابلة للتراجع، لكن ثلاثة ليست كذلك، والنماذج تقترح تلك الثلاثة بالذات بثقة تامة: git reset --hard الذي يرمي بحسب وثائق Git نفسها التغييرات غير المسجلة في شجرة العمل، وgit clean -fd الذي يحذف الملفات غير المتعقَّبة، وgit push --force الذي يستبدل الفرع على الخادم بنسختك وقد يمحو عمل شخص آخر. والقاعدة بسيطة: الأمر الذي لا تستطيع شرحه لا يُنفَّذ، وقبل أي من هذه الثلاثة خذ git status.
والخطر الثاني يخص اللصق لا التنفيذ: فكل diff أو ملف تضعه في محادثة قد غادر جهازك، وما يجري له يعتمد على خطة تلك الخدمة وإعداداتها وهو مكتوب على صفحة استعمال البيانات لديها. وهذا لا يمثل مشكلة لمشروع شخصي؛ أما شفرة العميل فتحتاج إذنا أولا. ولمعرفة كيف يمكن الدفع لكل أداة من إيران انظر دليل الشراء، ولاختيارنا الحالي بين نماذج البرمجة انظر أفضل ذكاء اصطناعي للبرمجة.
المصادر: git-scm: git reset git-scm: git clean git-scm: git push, the force option Anthropic: supported countries Google: where the Gemini web app is available
حدود هذه النصيحة
يغطي هذا الدرس شخصا واحدا على فرع واحد. وكل ما يضيفه العمل الجماعي بقي خارجا وكل جزء منه يريد درسه الخاص: التفريع، والدمج وحل التعارض، وrebase، ومراجعة الشفرة وطلبات الدمج، والملفات الكبيرة التي لم يُبنَ Git لها. وثمة حد أكبر يُقال أقل: Git مبني للملفات النصية، فإن كان ما يتغير في مشروعك يعيش في قاعدة بيانات لا في ملفات، فإن Git لا يراه. وموقع ووردبريس بهذا الشكل بالضبط، ولهذا أيضا لا يُعد وجود Git للقالب وحده نسخة احتياطية للموقع.
من عملنا نحن
هذا الموقع نفسه ليس له مستودع Git ويُحرَّر على خادم حي. والذي حل محله إضافة محرر القوالب التي كتبناها: فقبل كل حفظ تضع نسخة من الملف جانبا، باسم فيه التاريخ والساعة زائد ستة محارف عشوائية، وتحتفظ بآخر عشرين نسخة من كل ملف وتحذف الأقدم، ولها سجل أحداث بسقف مئتي سطر. وبعد الكتابة تحلل الملف الجديد بـtoken_get_all مع الراية TOKEN_PARSE، لأن php -l وproc_open كليهما معطلان على هذا الخادم؛ وإن لم يُحلَّل عادت تلك النسخة السابقة تلقائيا. وهذا قريب من الحد الأدنى لما يُسمى نظام إصدارات، ومسافته عن Git ثلاثة أشياء بالضبط: رسالة تقول لماذا، ورابط بين ملفين تغيرا معا، وتاريخ غير محدود بعشرين نسخة.
اسئلة متابعة حقيقية
هل أحتاج Git لمشروع شخص واحد؟
نعم، لكن ليس للسبب الذي يُقال عادة. فالسبب ليس النسخ الاحتياطي، إذ للنسخ طرق أبسط؛ بل أنك بعد ستة أشهر تكون الوحيد الذي عليه أن يفهم لماذا كُتب هذا السطر. وGit هو ما يحفظ جواب ذلك السؤال.
ما الفرق بين git pull وgit fetch؟
يجلب fetch تغييرات الخادم دون أن يمس عملك، فتستطيع أن تراها أولا. أما pull فيفعل الشيء نفسه ثم يدمجها فورا في فرعك. وحين لا تكون واثقا، ابدأ بـfetch.
كتبت رسالة الـcommit خطأ، هل أستطيع تغييرها؟
إن لم تكن قد دفعت بعد، فإن git commit --amend يغير رسالة آخر commit وينتهي الأمر. أما إن كنت قد دفعت، فهذا يعيد كتابة التاريخ ويسبب متاعب لكل من سحب ذلك الفرع؛ وفي مستودع مشترك يُفضَّل ترك الرسالة الخاطئة كما هي.