الوحدة 1 · نموذج Git
قراءة السجلّ: الـ commits كرسم بياني
16 دقراءة 4 داختر بحكمة
الدرس في لمحة
اقرأ سجلّ الـ repository بـ git log و git show و git diff، وسمِّ أي commit نسبةً إلى الـ HEAD، وتخيّل السجلّ رسمًا بيانيًا من اللقطات المرتبطة بآبائها.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
صار في موقعك الشخصي بضعة commits الآن. بعد ستة أشهر سيصبح فيه المئات، والسؤال الذي ستطرحه فعلًا لن يكون «ما هو السجلّ؟» بل شيئًا أدقّ: متى تعطّل الـ footer، وكيف كان هذا الملف قبل إعادة التصميم، وأيّ commit أضاف ذلك اللون. قراءة السجلّ جيدًا هي ما يجعلك تجيب عن هذه الأسئلة في ثوانٍ.
العرض اليومي
الأمر git log وحده يطبع كل commit، الأحدث أولًا، مع المعرّفات الكاملة والتواريخ. إنه شامل ومُتعب. هذه هي الصيغة التي تستحق الحفظ:
git log --oneline --graph --all* e5d81c0 (HEAD -> main) Merge branch 'dark-mode'
|\
| * d4a7f20 (dark-mode) Add dark mode colors
* | c39be11 Add projects page
|/
* b2e04f3 Add navigation bar with base styles
* a1c9d72 Add home pageاقرأه من الأسفل إلى الأعلى لتتبع الترتيب الزمني. كل * هي commit، والخطوط تبيّن أيّ commit جاء من أيّ commit. وبين الأقواس أسماء دالّة (labels): main و dark-mode فرعان، و HEAD -> main تعني أنك على main. الخيار --all مهم: دونه يعرض Git فقط الـ commits التي يمكن الوصول إليها من مكانك، ولن يبقى خط dark-mode ظاهرًا إلا لأنه دُمج.
الناتج الطويل يُفتح في أداة تصفّح (pager). استخدم الأسهم أو المسافة للتمرير و q للخروج.
مرشّحات مفيدة يمكن جمعها كلها: -n 5 (آخر خمسة)، و --stat (أيّ الملفات تغيّرت)، و -p (الـ diffs كاملة)، و --author="Maya"، و --since="2 weeks ago"، و -- index.html (فقط الـ commits التي لمست ذلك الملف).
الـ commits تشكّل رسمًا بيانيًا
الناتج أعلاه تمثيل لـ رسم بياني موجَّه غير دوري (directed acyclic graph)، أو DAG. موجَّه لأن كل commit يشير إلى أبيه. وغير دوري لأنك لا تستطيع تتبّع الآباء والعودة إلى حيث بدأت؛ فلا يمكن لـ commit أن يكون جدًّا لنفسه. معظم الـ commits لها أب واحد. الـ root commit لا أب له. والـ merge commit له أبوان.
احتفظ بهذه الصورة في ذهنك. في القسم الثاني سترى أن الـ branch ليس أكثر من واحد من هذه الأسماء الدالّة، وأن كل أمر متعلّق بالفروع إما يحرّك اسمًا أو يضيف دائرة.
تسمية الـ commits
تستطيع تسمية أي commit بمعرّفه، ويقبل Git أقصر بادئة لا لبس فيها، وهي عادةً 7 أحرف. المعرّفات hashes مشتقّة من محتوى الـ commit وبياناته الوصفية وأبيه، لذا لا تتغيّر أبدًا، ولا يشترك commitان مختلفان في المعرّف نفسه عمليًا.
غالبًا ما يكون العدّ انطلاقًا من مكانك أسهل:
HEADهو الـ commit الذي أنت عليه.HEAD~1(أوHEAD~) هو أبوه، وHEAD~3هو ثلاثة أجيال إلى الخلف، مع تتبّع الأب الأول في كل مرة.HEAD^2هو الأب الثاني لـ merge commit؛ وفيe5d81c0أعلاه هوd4a7f20.- اسم الفرع يصلح في أي مكان يصلح فيه الـ commit:
dark-mode~1هوb2e04f3.
النظر داخل الـ commits
git show c39be11 # message, author, date and the diff it introduced
git show HEAD~2:styles.css # the whole file as it was in that snapshot
git diff a1c9d72 HEAD # everything that changed between two snapshots
git diff HEAD~3 HEAD -- styles.css # the same, for one file onlyيقبل git diff أي commitين لأن كلًا منهما لقطة كاملة. ويُحسب الـ diff عند الطلب بمقارنتهما. وكذلك الحال مع الـ diff الذي يطبعه git show: إنه لقطة هذا الـ commit مقارنةً بلقطة أبيه.
تحقيق حقيقي
هكذا تتكامل هذه الأوامر. يخبرك صديق أن الـ footer في صفحة مشاريعك اختفى، وأنت متأكّد أنه كان موجودًا الأسبوع الماضي. ابدأ بتضييق السجلّ إلى الملف المعنيّ:
git log --oneline --since="1 week ago" -- projects.html8f1e2aa Move project cards into a grid
c39be11 Add projects pageمشتبهان اثنان. انظر إلى الأحدث بالكامل:
git show 8f1e2aa -- projects.htmlيُظهر الـ diff كتلة <footer> باللون الأحمر، أُزيلت مع ترميز القائمة القديمة. هذا هو الجاني، وجدته في أقل من دقيقة. ولتأخذ ترميز الـ footer القديم دون إرجاع أي شيء، اطبع الملف كما كان في الـ commit الأب وانسخ ما تحتاجه:
git show 8f1e2aa~1:projects.htmlلم يغيّر هذا التحقيق ملفًا واحدًا ولا commitًا واحدًا. قراءة السجلّ آمنة دائمًا، فافعلها بحرية وكثيرًا. معظم «حالات الطوارئ في Git» التي رأيتها كانت في الحقيقة مشكلات قراءة: شخص ما ذُعر قبل أن ينظر إلى الرسم، والجواب كان موجودًا في git log منذ البداية.
رأيت أسماء مثل main و dark-mode معلّقة على الـ commits. يبدأ القسم الثاني بشرح حقيقة هذه الأسماء، ولماذا يكاد إنشاء واحد منها لا يكلّف شيئًا.
أهم النقاط
- السجلّ رسم بياني موجَّه غير دوري، يشير فيه كل commit إلى أبيه، ويشير الـ merge commit إلى أبوين.
git log --oneline --graph --allيرسم الرسم البياني في الطرفية، بما فيها الفروع التي لست عليها.git show <commit>يطبع رسالة commit واحد وتغييراته؛ وgit show <commit>:<path>يطبع ملفًا كما كان حينها.HEAD~1هو الـ commit الذي يسبق الـ commit الذي أنت عليه، وHEAD~3ثلاث خطوات إلى الخلف عبر الآباء الأوائل.git diff A Bيقارن أي لقطتين، و-- <path>يحصر المقارنة في ملف واحد.