CI/CD والبنية التحتية كرمز
داخليات Git والعمليات المتقدمة
4 دقيقة للقراءة
أسئلة Git تتجاوز الأوامر الأساسية في مقابلات DevOps/SRE. دعنا نتقن الداخليات والعمليات المتقدمة.
نموذج كائنات Git
فهم داخليات Git يُبهر المقابلين:
Git يخزن 4 أنواع من الكائنات:
1. blob - محتويات الملف
2. tree - بنية المجلد
3. commit - لقطة مع بيانات وصفية
4. tag - مرجع مسمى للـ commit
# عرض نوع الكائن
git cat-file -t <sha>
# عرض محتوى الكائن
git cat-file -p <sha>
# قائمة جميع الكائنات
find .git/objects -type f
كيف تعمل الـ Commits
┌──────────┐
│ commit │
│ (sha: a1)│
└────┬─────┘
│ يُشير إلى
┌────▼─────┐
│ tree │
│ (sha: b2)│
└────┬─────┘
┌──────────┴──────────┐
┌────▼─────┐ ┌────▼─────┐
│ blob │ │ tree │
│ (ملف) │ │ (مجلد) │
└──────────┘ └──────────┘
عمليات Git المتقدمة
Rebase مقابل Merge
| الجانب | Merge | Rebase |
|---|---|---|
| التاريخ | يحفظ جميع الـ commits | تاريخ خطي |
| التعارضات | مرة واحدة أثناء الدمج | لكل commit |
| الأمان | آمن للفروع المشتركة | يُعيد كتابة التاريخ |
| متى تستخدم | الفروع المشتركة | الفروع المحلية/الميزات |
# Rebase تفاعلي (إعادة الترتيب، الدمج، تعديل الـ commits)
git rebase -i HEAD~5
# Rebase على main
git checkout feature
git rebase main
# لا تعمل rebase للفروع المشتركة أبداً!
# "إذا شككت، لا تعمل rebase"
سؤال مقابلة: "متى يجب أن تستخدم rebase مقابل merge؟"
الجواب: استخدم rebase للفروع المحلية للميزات للحفاظ على تاريخ نظيف. استخدم merge للفروع المشتركة/العامة للحفاظ على التاريخ وتجنب إعادة كتابة commits يعتمد عليها الآخرون.
Cherry-Pick
# طبق commit(s) محددة على الفرع الحالي
git cherry-pick <commit-sha>
# Cherry-pick بدون commit
git cherry-pick --no-commit <sha>
# Cherry-pick نطاق
git cherry-pick A^..B
Git Bisect
ابحث عن الـ commit الذي أدخل الخلل:
# ابدأ bisect
git bisect start
# علّم الحالي (المعطل) كسيء
git bisect bad
# علّم commit معروف أنه جيد
git bisect good <sha>
# Git يُحضر commit الأوسط، اختبر وعلّم:
git bisect good # أو
git bisect bad
# استمر حتى يجد Git أول commit سيء
# عند الانتهاء:
git bisect reset
Reflog - شبكة أمانك
# عرض reflog (تاريخ حركات HEAD)
git reflog
# استرجع commits "المحذوفة"
git checkout -b recovery <sha-from-reflog>
# تراجع عن rebase سيء
git reset --hard HEAD@{5}
استراتيجيات سير عمل Git
التطوير المبني على الجذع
main ─────●─────●─────●─────●─────●
\ /
●─────●───
(فرع ميزة قصير العمر)
- commits مباشرة إلى main
- أعلام الميزات للميزات غير المكتملة
- يتطلب CI/CD واختبار جيد
- يُستخدم من Google، Facebook
GitFlow
main ─────●───────────────●─────────
\ /
develop ───●───●───●───●───●───●───●───
\ \ /
feature ●───● ●───●
release ●───●───●
- فروع develop وmain منفصلة
- فروع feature، release، hotfix
- أفضل للإصدارات المجدولة
- أكثر تعقيداً، حمل أكبر
GitHub Flow
main ─────●─────●─────●─────●─────●
\ / \ /
feature ●───●─── ●───●
(PR) (PR)
- بسيط: main + فروع الميزات
- Pull requests للمراجعة
- النشر من main
- توازن جيد لمعظم الفرق
أسئلة المقابلة
س: "كيف ستسترجع commit بعد تشغيل git reset --hard؟"
# تحقق من reflog للـ commit المفقود
git reflog
# ابحث عن SHA للـ commit قبل الـ reset
# أنشئ فرعاً منه
git checkout -b recovery <sha>
# أو reset إليه
git reset --hard <sha>
س: "ما الفرق بين git reset وgit revert؟"
| العملية | التأثير | التاريخ | حالة الاستخدام |
|---|---|---|---|
reset |
يُحرك HEAD، قد يتجاهل commits | يُعيد الكتابة | التنظيف المحلي |
revert |
يُنشئ commit جديد يلغي التغييرات | يحفظ | الفروع المشتركة |
# Reset: يُحرك HEAD للخلف (يُعيد كتابة التاريخ)
git reset --hard HEAD~3
# Revert: يُنشئ commit جديد (آمن للمشترك)
git revert <sha>
س: "دفعت بالخطأ أسراراً إلى مستودع عام. كيف تصلحه؟"
# 1. احذف من التاريخ باستخدام filter-branch أو BFG
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch secrets.env" HEAD
# أو استخدم BFG Repo Cleaner (أسرع)
bfg --delete-files secrets.env
# 2. Force push (نسق مع الفريق!)
git push --force-with-lease
# 3. قم بتدوير جميع بيانات الاعتماد المكشوفة فوراً!
# 4. GitHub قد يُخزن مؤقتاً - تواصل مع الدعم
التالي، سنغوص في تصميم خطوط CI/CD—كفاءة أساسية في DevOps/SRE. :::