المقدمة #
اليوم كان آخر يوم من الـبوتكامب اللي كنت أدرّس فيه، ولأن لاحظت إن بعض الناس بعدهم محتاجين مساعدة؛ كتبت هالمدونة عشان ألخّص كل البوتكامب في تدوينة قصيرة نسبياً، يلا نبدأ!
اليوم الأول #
المصطلحات: #
- Directory -> فولدر
- Terminal -> بالمختصر CMD
- Git Bash -> سي ام دي لكن مع قدرات باش تبع لينكس
الخطة: #
- وش هو git
- تاريخ git.
- كيف يشتغل git من تحت
- شرح أوامر “porcelain” و “plumbing”
وش هو git #
git هو نظام التحكم بالإصدارات القياسي حالياً. نظام التحكم بالإصدارات يعني نظام يسمح للناس يشوفون ويعدلون ويحذفون الإصدارات القديمة من مشروع. يمكن كثير منكم يعرف GitHub، اللي هو نسخة مستضافة من git. والحين بأقولكم ليش اخترع git.
تاريخ git #
git اخترع بواسطة لينوس تورفالدز، مخترع لينكس، في أسبوع واحد بس لأنه كانوا مخربين رخصة نظامهم القديم لإدارة الأكواد وقتها واللي كان اسمه BitKeeper. إذا حابين تعرفون أكثر، افتحوا جوجل، أنا بس بأبدأ بالجزء العملي.
كيف يشتغل git من تحت #
كيف كان أغلب الناس يسوون التحكم بالإصدارات بدون git #
كان الواحد ياخذ نسخة من الدليل الحالي ويحطها في فولدر منفصل اسمه “versions”، ويمكن يستخدم روابط رمزية (symlinks) عشان يقلل حجم التخزين.
كيف يسويه git #
الطريقة الطويلة #
git أساساً يسوي نظام ملفات بعنوان “محتوى موجه” يسمونه “object Database”، وهو شبيه بمخزن key:value حيث كل مفتاح هو الـ hash الخاص بالملف (والـ hash يكون باستخدام SHA-1).
قاعدة البيانات هذه تحفظ في فولدر objects داخل المجلد المخفي .git. والأوبجكتات تنحط في فولدرات فرعية بناءً على أول بايت من الـ key اللي يستخدم لتسمية الفولدر الفرعي والباقي يستخدم لتسمية الملف اللي يحتوي على الأوبجكت. السبب في هالطريقة هو تقليل عدد الملفات في كل فولدر، لأن بعض أنظمة الملفات مثل FAT-32 تسمح حوالي 65,536 ملف في الفولدر. وللعلم، الـ blob (اللي هو الأوبجكت في هالسياق) يحتوي بس على محتويات الملف وما يحتوي على اسم الملف أو أي بيانات إضافية.
كيف يحل git مشكلة عدم وجود اسم الملف؟ يستخدم “git tree object”. تقدر تفكر بالشجرة كأنها فولدر في نظام الملفات، فالشجرة تتكون من أشجار ثانية وبلوبات (blobs)، وهذا يساعد النظام على إعادة استخدام الفروع الفرعية. بمجرد إنشاء الشجرة تحفظ في الـ object database، لكن ممكن ننسى الـ id للشجرة اللي فيها التغيير، فنقرر نكتبها في ملف ونضيف رسالة توضح التغيير ومعلومات عن الكاتب. وكمان يكون مفيد نعرف كيف تغير المشروع مع الوقت، فكل مرة نسوي تغيير، نخزن مرجع للتغيير السابق. المعلومات عن تغيير واحد نسميها “commit”، والـ commits هم أوبجكتات بعد، فيتنحطون في قاعدة البيانات. نقدر نستخدم commit ids عشان نرجع لحالة المشروع في أي وقت. ونقدر نشوف تاريخ التغييرات. للأسف، git يستخدم SHA-1 للـ commit ids واللي مو سهل كتابتها يدويًا لأنها طويلة جداً، عشان كذا git يستخدم “branches” وهي مراجع سهلة للإشارة للـ commits، ونقدر نعطيها أي اسم نبيه. المرة الجاية إذا نبي نشوف حالة المشروع، نستخدم اسم الفرع بدلاً من الـ commit id.
لاحظ إن الـ commits ثابتة (immutable) لأنها محسوبة من المحتوى، فإذا تغير المحتوى يتغير الـ id، بينما الفروع (branches) قابلة للتغيير، نقدر نعدلها بأي وقت. في الحقيقة، كل مرة تسوي commit في مستودع، الفرع يتحدّث تلقائياً للإشارة للـ commit الأخير.
الطريقة المختصرة #
نظام الملفات الموجه بالمحتوى #
git يسوي نظام ملفات موجه بالمحتوى يسمونه “object database”. يشتغل مثل مخزن key:value، حيث كل مفتاح هو الـ SHA-1 hash للملف.
هيكل قاعدة البيانات للأوبجكتات #
- مكان التخزين: قاعدة البيانات تحفظ في فولدر objects، الموجود داخل المجلد المخفي .git.
- تنظيم الفولدرات الفرعية: الأوبجكتات تنحط في فولدرات فرعية بناءً على أول بايت من الـ hash (اللي يسمّي الفولدر) والباقي يستخدم لتسمية الملف. هالطريقة تقلل عدد الملفات في كل فولدر على أنظمة الملفات (مثل FAT-32) اللي لها حدود.
أوبجكتات الـ Blob #
- التعريف: الـ blob هو أوبجكت يحتوي بس على محتويات الملف.
- القيود: الـ blobs ما يحفظون أسماء الملفات أو بياناتها الإضافية.
أوبجكتات الـ Tree #
- الهدف: عشان يحلون مشكلة غياب اسم الملف، git يستخدم شجرة (tree object).
- الوظيفة: الشجرة تشتغل مثل الفولدر، تحتوي على مراجع لـ blobs (الملفات) وأشجار ثانية (الفولدرات الفرعية)، وهذا يسمح بإعادة استخدام الفروع الفرعية.
أوبجكتات الـ Commit #
- لقطة للتغيير: لما يصير تغيير، git يسوي commit object يحتوي على:
- رسالة توضح التغيير.
- معلومات عن الكاتب.
- مرجع للتغيير السابق، وبكذا يسوي تاريخ.
- الثبات: الـ commits ثابتة لأنها محسوبة من المحتوى؛ أي تغيير يغير الـ id.
الفروع كمراجع سهلة للمستخدم #
- التبسيط: بما إن الـ commit ids (SHA-1 hashes) طويلة، git يستخدم الفروع كمرجعات قابلة للتعديل للـ commits.
- الاستخدام: الفروع تسمح للمستخدمين يشيرون إلى commit باسم بسيط، ويتحدث تلقائياً لما يصير commit جديد.
هذا هو باختصار كيف يشتغل git من تحت: #
- git يخزن الأوبجكتات في الـ object database.
- أنواع الأوبجكتات: Commits, Trees, Blobs.
- الـ blob يمثل محتوى الملف.
- الشجرة (tree) تمثل الفولدر.
- الـ commit هو لقطة من حالة المشروع.
الحين بنبدأ باستخدام git عملياً #
إذا كنت على ويندوز، أول شيء ثبت Chocolatey من هالموقع. تأكد إنك تفتح الـ Terminal بوضع Administrator:
https://chocolatey.org/install
إذا كنت على لينكس، استخدم مدير الحزم، ما أعتقد تحتاج أوضح لك الطريقة.
إذا كنت على ماك، شغل هالأوامر:
xcode-select --install
وبرضه إذا كنت على ماك، ثبت Homebrew لأنك بتحتاجه:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
كل الأوامر موجودة في سيرفر الديسكورد بقناة الموارد. يا جماعة الويندوز، لازم من هاللحظة تتحولون لـ git bash.
الحين بنستخدم بعض أوامر git للوصول لقاعدة البيانات للأوبجكتات. أول شي استنساخ هذا الريبو:
git clone https://github.com/abo3skr2019/Bootcamp-Example
أو:
git clone [email protected]:abo3skr2019/Bootcamp-Example
النسخة اللي باستخدام SSH أفضل، لكن تحتاج إعدادات للوصول للمستودعات الخاصة، فبتجاوزها الحين.
بعد استنساخ الريبو، ادخل للفولدر:
cd Bootcamp-Example
الحين شغل هالأوامر:
الأمر هذا يعطيك تاريخ الـ commit في الفرع الحالي:
git log --oneline
أمر ls-tree يعتبر من أوامر “plumbing”، ما بتستخدمه كثير، يعرض لك محتويات الشجرة، وبما إن الـ commits مجرد أشجار مع معلومات زيادة، نقدر نوصل للأشجار باستخدام الأمر نفسه:
git ls-tree $Commit-ID
git ls-tree $Tree-ID
والحين تشوف المحتويات.
الحين جرّب تسوي شجرة متداخلة باسم nested-tree تحتوي على blob باسم nested-blob. سو كل هالعمليات من الـ Terminal بدون استخدام محررات النصوص. إذا حاب تضيف محتوى لملف من الـ Terminal، استخدم:
echo "CONTENT" >> $Filename
وإذا حاب تسوي commit لملف، استخدم الأمرين هذول: الأول يسوي عملية “staging” يعني تحضير التعديلات للتسجيل:
git add $File
والثاني يسوي الـ commit مثل ما شرحنا قبل:
git commit -m "$message"
وبعدين تأكد إن كل المشاركين قدروا يسوون هالشي!
اليوم الثاني #
اليوم بيكون عملي تقريباً بالكامل.
أول شيء ثبت hugo، الأمر لكل الأنظمة موجود في قناة الموارد بسيرفر الديسكورد.
الحين بما إنكم ثبتتم hugo، بأشرح لكم وش هو:
hugo هو مولّد مواقع ثابتة، يعني يولّد صفحات HTML ثابتة من المحتوى اللي تعطيه، وفي حالتنا هذه ملفات markdown لأنها الأكثر استخداماً في الصناعة.
مع إنك تقدر تكتب HTML أو تستخدم emacs org mode أو pandoc وغيره.
فأول شيء، كيف يشتغل markdown؟ markdown هو لغة ترميز، يعني لما تكتب # يتحول مباشرةً لـ H1 في HTML، وكل ما تزيد # يزيد مستوى العنوان، فـ ## هو H2، ### هو H3 وهكذا.
قبل ما أبدأ أشرح لكم markdown بشكل عملي، خل نشوف إذا بعضكم يعرف هالصيغة لأنها مستخدمة في تطبيقات كثيرة مثل Notion, Obsidian, Whatsapp, Discord وغيرهم.
عشان تسمي كلمة بخط غامق تحيطها بنجوم مزدوجة “**"، وللتأكيد/الميل تحيطها بشرطة سفلية “_” أو بنجمة وحدة “*”.
وللربط مع شيء تستخدم هالصيغة [النص](الرابط)
.
يلا نبدأ نصنع هالمدونة. أول شيء ثبت hugo، مولّد المواقع الثابتة. إذا كنت على ويندوز، افتح Terminal بوضع Administrator باستخدام الاختصار (Win+X)، وبعدين في وضع الـ Administrator شغل الأمر هذا لتثبيت gohugo:
choco install hugo-extended
بعدين في git-bash، سو فولدر لمشاريعك:
mkdir Code-Projects
وبعدين ادخل له:
cd Code-Projects
بعدها شغل الأمر هذا عشان تنشئ موقع hugo:
hugo new site myBlog
وبعدين ادخل للفولدر اللي انخلق:
cd myBlog
بعدها ابتدي ريبو git:
git init
الحين بنضيف ثيم من موقع ثيمات Hugo، أنا بستخدم ثيم blowfish:
git submodule add -b main https://github.com/nunocoracao/blowfish.git themes/blowfish
الحين بنسوي ملف README، أول شي نحتاج نخلق ملف markdown فاضي اسمه README.md، فسنستخدم أمر touch:
touch README.md
تأكد إنك ما تكتب README غلط.
الحين بنضيف عنوان، افتح محرر الكود، أنا بستخدم vscode:
code .
وبعدين أضف في أعلى الملف هذا:
# Introduction
This is a blog made in the **"Create a blog Using git"** Boot-camp Presented by [*Abdulaziz Askar*](https://github.com/abo3skr2019)
بعدها شغل الأمر هذا عشان تضيف وتسجل تغييراتك في الريبو:
git commit -am "Hugo Init"
اليوم الثالث #
الحين بنضبط الثيم ونرفع المدونة على GitHub.
إعداد المدونة #
إعدادات الثيم #
أول شيء نسخ الإعدادات:
cp theme/blowfish/config config -r
احذف ملف hugo.toml اللي انولد تلقائياً:
rm hugo.toml
بعدين افتح vscode:
code .
وبعدين في ملف Hugo.toml، فك التعليق عن السطر:
theme = "blowfish"
وفي ملف languages.en.toml، فك التعليق وعدل هذي الحقول:
[params.author]
name = "Your name here"
email = "[email protected]"
headline = "I'm only human"
bio = "A little bit about you"
وبرضه بعض بيانات التواصل إذا حاب، بس تأكد تفك التعليق عن الروابط وتنهي القوس المربع عشان الموقع يشتغل:
# links = [
# { email = "mailto:hello@your_domain.com" },
# { github = "https://github.com/username" },
# { linkedin = "https://linkedin.com/in/username" },
# { x-twitter = "https://twitter.com/username" },
# { youtube = "https://youtube.com/username" },
# ]
وفي ملف menus.en.toml، فك التعليق عن هذي:
[[main]]
name = "Blog"
pageRef = "posts"
weight = 10
وفي ملف params.toml، غيّر قيمة ShowRecent
إلى True.
خل نكتب محتوى #
عشان تكتب محتوى في hugo، نستخدم الكلمة المفتاحية “new” ونحدد إنّه محتوى. وهناك طرق كثيرة لتنظيم المحتوى، تقدر تسويه بفولدرات وفهارس مثل:
hugo new content posts/25/march/Git-bootcamp/index.md
أو تقدر تسوي ملف markdown واحد مثل:
hugo new content posts/25/march/Git-bootcamp.md
الحين بما إننا سوينا المحتوى، المفروض ينخلق ملف بالموقع المحدد ويكون شكله كالتالي:
+++
title = 'Filename'
date = Current Date
draft = false
+++
هذا يسمى “frontmatter” وهو مثل metadata نقدر نحط فيه أشياء مثل الوسوم والتصنيفات مثل:
+++
title = 'Filename'
date = Current Date
draft = false
tags :
- Tag1
- Tag2
- Tag3
categories :
- Cat1
- Cat2
- Cat3
+++
الحين بما إننا خلصنا من الـ frontmatter، نضيف محتوى: مثل ما قلت، hugo يستخدم تنسيق markdown للمحتوى، فخل نستخدم شوية markdown!
+++
title = 'Filename'
date = Current Date
draft = false
tags :
- Tag1
- Tag2
- Tag3
categories :
- Cat1
- Cat2
- Cat3
+++
# This is a Sample Post
For the Git Bootcamp Summary
بعدين تأكد من شغلك في vscode أو من خلال git bash، شغل الأمر:
hugo server
ودخل على الموقع من خلال: https://localhost:1313
إذا كان موقعك يشتغل، يلا نكمل. أضف كل تغييراتك وسجلها في ريبو git:
git commit -am "Setup Theme"
خل نرفع ريبو git على GitHub #
فيه 3 طرق: الطريقة السهلة، والطريقة الأكثر صعوبة، والطريقة الأصعب.
الطريقة السهلة #
في vscode، افتح قائمة التحكم بالمصدر سواء باستخدام الماوس أو الاختصار (Alt+NumPad9)، بعدين اضغط على “Publish branch” واتبع الخطوات اللي يوجهك لها vscode. ملاحظة: تأكد إن الريبو عام، لأنه إذا كان خاص ما تقدر تنشر على GitHub Pages.
الطريقة الأكثر صعوبة #
ثبت GitHub CLI:
choco install gh
بعدين استخدم GitHub CLI بتنفيذ الأمر:
gh repo create myBlog --public --source=. --remote=origin
الطريقة الأصعب #
- روح على GitHub
- سو حساب إذا ما عندك واحد.
- اضغط على علامة “+” في أعلى يمين الصفحة → New repository.
- سمي الريبو، مثلاً “Blog”. بعدين انسخ رابط الريبو وشغل:
git remote add origin https://github.com/$your-username/myBlog
تأكد إن الريبو انضاف:
git remote -v
أخيراً، ادفع الريبو المحلي إلى GitHub:
git branch -M main # يعيد تسمية الفرع إلى 'main' إذا احتاج
git push -u origin main
بعد كذا،
خل ننشر المدونة على GitHub Pages #
- افتح GitHub وروح لريبوك، المفروض يكون على الرابط
https://github.com/$your-username/myBlog
- روح لإعدادات الريبو، المفروض يكون على الرابط
https://github.com/$your-username/myblog/settings
- روح لقسم Pages وبعدين اضغط على القائمة تحت “source”، المفروض يقول “deploy from branch”. اضغط عليها وغيرها إلى “GitHub Actions”. ولما يعيد تحميل الموقع، المفروض يختلف شكل الموقع.
- تحت خيار GitHub Actions، المفروض يقول “Use a suggested workflow, browse all workflows, or create your own.” اضغط على “Browse all Workflows”، وبيوديك لهالرابط
https://github.com/$your-username/myblog/actions/new
. في الصفحة دور على hugo واضغط على “configure”، وبعدين في أعلى اليمين اضغط على “commit changes”.
هالخطوات بتنشر موقعك على GitHub Pages، وتقدر تلقى رابط موقعك هنا: https://github.com/$your-username/myblog/settings/pages
قراءة / مشاهدة إضافية #
- هذا فيديو قصير على يوتيوب يشرح كيف يشتغل git من تحت:
- هالدورة المجانية على يوتيوب من Primagen:
- هذي محاضرة من أحد مؤسسي GitHub:
- وثائق ثيم Blowfish
- وثائق goHugo