كيف يرى Git التاريخ؟
تتبعنا في الدرس السابق علاقة الـ Parent من Commit إلى الذي سبقه:
Commit D
│
▼
Commit C
│
▼
Commit B
│
▼
Commit Aفي هذا المثال يبدو التاريخ كأنه خط واحد. لكنه لا يبقى كذلك عندما تتفرع منه مسارات مختلفة أو تلتقي هذه المسارات لاحقا.
من السلسلة إلى الرسم البياني
لنفترض أن لدينا هذا التاريخ:
Commit C
│
▼
Commit B
│
▼
Commit Aإذا بني Commit C و Commit D كل منهما على Commit B فسيشير كلاهما إلى الـ Parent نفسه:
Commit C Commit D
│ │
└──────┬───────┘
▼
Commit B
│
▼
Commit Aلم يعد التاريخ سلسلة واحدة. أصبحت لدينا عقد مرتبطة بأسهم. و قد تنطلق عدة أسهم نحو الـ Parent نفسه.
الرسم البياني للـ Commits (Commit Graph)
يمكننا النظر إلى كل Commit على أنه عقدة (Node) و إلى كل علاقة Parent على أنها سهم يصلها بعقدة سابقة:
Commit C Commit D
│ │
└──────┬───────┘
▼
Commit Bتشكل هذه العقد و العلاقات ما يسمى Commit Graph. و لا يحتاج Git إلى قائمة منفصلة ترتب كل الـ Commits فالعلاقات بينها تحدد طرق الرجوع في التاريخ.
لماذا يسمى DAG؟
قد تسمع أحيانا أن Git يعتمد على Directed Acyclic Graph أو اختصارا DAG.
- Directed لأن كل علاقة تتجه من Commit إلى Parent سابق.
- Acyclic لأن اتباع علاقات الـ Parent لا يمكن أن يعيدنا إلى الـ Commit الذي بدأنا منه.
يسجل الـ Commit معرفات الـ Parents عند إنشائه ثم يبقى الـ Object المخزن ثابتا. لو غيرنا Parent لاحقا لتغيرت بيانات الـ Commit و نتج معرف جديد. لذلك لا يمكن تعديل Commit سابق كي يشير إلى Commit جاء بعده و يغلق حلقة.
هذه العلاقات تتجه نحو الماضي:
Commit C
│
▼
Commit B
│
▼
Commit Aأما هذا الشكل فيصنع حلقة تعود إلى نقطة البداية:
Commit C
│
▼
Commit B
│
▼
Commit A
│
└─────────┐
│
▼
Commit Cلا يمكن أن تنتج هذه الحلقة من علاقات Parent سليمة ولذلك يوصف الرسم البياني بأنه Acyclic.

كيف يقرأ Git التاريخ؟
عندما تعرض سجل المشروع باستخدام:
git logيبدأ Git افتراضيا من الـ Commit الحالي ثم يتبع جميع علاقات الـ Parent. لذلك لا يعرض بالضرورة كل Commit Object موجود في قاعدة البيانات، بل يعرض الـ Commits التي يمكن الوصول إليها من نقطة البداية.

لنجرب بأنفسنا
الـ Terminal بجانبك يحتوي على مستودع فيه سلسلة من الـ Commits.
اعرض التاريخ المختصر:
git log --onelineانسخ المعرف المختصر لأول سطر و استخدمه مكان <commit-hash>:
git cat-file -p <commit-hash>انسخ المعرف الموجود في سطر parent و استخدمه مكان <parent-hash>:
git cat-file -p <parent-hash>كرر الأمر بالمعرف الجديد حتى تصل إلى Commit لا يحتوي على سطر parent.
الصورة الحالية
أصبح لدينا الآن نموذجان مترابطان:
Commit
├── Tree
│ └── Blob
└── Parent
└── Commitيقود معرف الـ Tree من الـ Commit إلى حالة الملفات، بينما تقود علاقات الـ Parent إلى Commits سابقة و تبني Commit Graph.
لكن الوصول إلى Commit ما زال يتطلب معرفا طويلا. في الدرس التالي سنتعرف إلى References التي تمنح هذه المعرفات أسماء يسهل استخدامها.
الفحص الآلي يؤكد أن الـ Commit الأول بلا parent. أما تتبع السلسلة فهو تمرين قراءة: قارن كل معرف تستخرجه بالمعرف الذي تقرأه في الخطوة التالية.