الوحدة 4 · عادات احترافية
رسائل الـ Commit والـ Tags والإصدارات
15 دقراءة 4 داكتشف الخطأ
الدرس في لمحة
اكتب رسائل commit تشرح السبب، واتبع صيغة Conventional Commits حين يستخدمها الفريق، وعلّم الإصدارات بـ tags مشروحة (annotated)، وانشر GitHub Release بملاحظات مولَّدة.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
بعد ستة أشهر من الآن ستشغّل git log على موقعك الشخصي باحثًا عن اللحظة التي تعطّل فيها الثيم الداكن، وستقرأ رسائل كتبتها أنت في الماضي. “updates” و “fix” و “asdf” لن تساعدك. فائدة السجلّ بقدر فائدة الكلمات المرفقة به. يدور هذا الدرس حول جعل هذه الكلمات ذات قيمة، ثم حول تسمية اللحظات المهمّة: الإصدارات.
كيف تبدو رسالة الـ commit الجيدة
لرسالة الـ commit سطر عنوان (subject line)، ثم سطر فارغ، ثم نص (body) اختياري:
Fix footer overlapping content on mobile
The footer used position: fixed, so on screens shorter than
the content it covered the last project card. Switch to a
normal flow footer and add bottom padding to the grid.
Closes #13الأعراف، وسبب وجودها:
- عنوان في حدود 50 حرفًا. إنه ما يعرضه
git log --onelineوقوائم الـ commits في GitHub وعناوين الـ pull requests؛ والعناوين الطويلة تُقتطع. - صيغة الأمر: “Fix” و “Add” و “Remove”، لا “Fixed” ولا “Adds”. واختبار مفيد: العنوان يُكمل الجملة “If applied, this commit will…”. وهو أيضًا يطابق الرسائل التي يكتبها Git بنفسه، مثل “Merge branch ‘footer’”.
- لا نقطة في نهاية العنوان.
- النص يشرح السبب، ويُلفّ عند نحو 72 حرفًا. الـ diff يبيّن أصلًا ما الذي تغيّر؛ وأنت وحدك تعرف السبب، والبديل الذي رفضته، والخطأ الذي يصلحه.
- التذييلات (trailers) في الأسفل:
Closes #13، أوCo-authored-by: Name <email>الذي يستخدمه GitHub لنسب العمل إلى شركاء البرمجة الثنائية.
استخدم git commit دون -m حين يحتاج التغيير إلى نص؛ فمحرّرك يسهّل كتابة الرسائل متعدّدة الأسطر. أما للتغييرات ذات السطر الواحد، فـ -m كافٍ.
الـ Conventional Commits
كثير من الفرق تعتمد صيغة منظّمة تُسمّى Conventional Commits:
feat(projects): add tag filter to projects page
fix(nav): close mobile menu when a link is clicked
docs: add setup steps to README
ci: run HTML check on pull requests
feat!: rename data-theme attribute to data-color-schemeالشكل هو type(optional scope): description. تعرّف المواصفة feat (feature جديدة) و fix (إصلاح خطأ)؛ وتضيف الفرق عادةً docs و style (تنسيق فقط، لا CSS) و refactor و perf و test و build و ci و chore. وعلامة ! قبل النقطتين، أو تذييل BREAKING CHANGE:، تعلّم تغييرًا يكسر التوافق مع المستخدمين الحاليين.
والمكسب هو الأتمتة. لأن النوع قابل للقراءة آليًا، تستطيع الأدوات توليد سجلّات التغيير (changelogs) واختيار الإصدار الدلالي (semantic version) التالي لك: fix يرفع رقم الـ patch (من 1.4.2 إلى 1.4.3)، و feat يرفع الـ minor (1.5.0)، والتغيير الكاسر يرفع الـ major (2.0.0).
عادةً ما تُبقي الـ Conventional Commits الوصف بأحرف صغيرة، وهذا يختلف عن الأسلوب ذي الحرف الأول الكبير أعلاه. وليس أيٌّ منهما خاطئًا. استخدم ما يستخدمه الـ repository أصلًا؛ فالاتساق يتفوّق على التفضيل الشخصي. وفي موقعك الشخصي، جرّب الـ Conventional Commits؛ فهي شائعة بما يكفي في الفرق لتؤتي هذه العادة ثمارها.
الـ Tags: تسمية لحظة
الفروع تتحرّك؛ أما الـ tags (الوسوم) فلا. الـ tag اسم دائم لـ commit واحد، يُستخدم لتعليم الإصدارات: الموقع الشخصي كما كان عند الإطلاق، وعند v1.1، وهكذا.
في Git نوعان. الـ tag الخفيف (lightweight) مجرد اسم يشير إلى commit. والـ tag المشروح (annotated) كائن كامل فيه اسم الواسم وتاريخ ورسالة. استخدم الـ tags المشروحة للإصدارات:
git tag -a v1.0.0 -m "Portfolio launch"
git tag # list tags
git show v1.0.0 # tag message, then the commit it points at
git tag -a v0.9.0 b2e04f3 -m "Preview for mentors" # tag an older commitتبقى الـ tags على جهازك حتى ترفعها، وهذا يفاجئ معظم الناس في المرة الأولى:
git push origin v1.0.0 # one tag
git push --follow-tags # commits plus any annotated tags that point at themتعامل مع الـ tag المرفوع على أنه دائم. إن وسمت الـ commit الخطأ ورفعته بالفعل، فانشر إصدارًا جديدًا (v1.0.1) بدل تحريك v1.0.0 من تحت أقدام من ربما استخدموه.
الـ GitHub Releases
الـ release (الإصدار) على GitHub هو tag مع عنوان وملاحظات وملفات اختيارية للتنزيل. افتح صفحة Releases في الـ repository، واختر Draft a new release، وحدّد الـ tag (أو أنشئ واحدًا)، ثم انقر Generate release notes: يسرد GitHub الـ pull requests المدموجة منذ الإصدار السابق، مع كاتبيها. حرّر الملاحظات حتى تصبح شيئًا يرغب إنسان في قراءته، ثم انشر.
والـ CLI يفعل الشيء نفسه في سطر واحد:
gh release create v1.0.0 --title "Portfolio v1.0.0" --generate-notesعناوين الـ pull requests الجيدة تصبح ملاحظات إصدار جيدة مجانًا، وهذا سبب إضافي لكون العادات السابقة تؤتي ثمارها.
الرسائل النظيفة والـ tags والإصدارات تجعل السجلّ مقروءًا. والخطوة الأخيرة جعل main جديرًا بالثقة دون أن تضطر إلى مراقبته بنفسك: فحوص آلية على كل pull request، وقواعد تفرضها.
أهم النقاط
- سطر العنوان الجيد قصير وبصيغة الأمر ومحدّد (“Fix footer overlap on mobile”)؛ والنص، بعد سطر فارغ، يشرح السبب.
- الـ Conventional Commits تسبق العنوان بنوع مثل
featأوfixأوdocs، وهذا يسمح للأدوات باستنتاج أرقام الإصدارات وسجلّات التغيير. - الـ tags المشروحة (
git tag -a v1.0.0 -m "…") تسجّل من وسم ماذا ومتى؛ وهي النوع المناسب للإصدارات. git pushلا يرسل الـ tags؛ ارفعها بـgit push origin v1.0.0أوgit push --follow-tags.- الـ GitHub Release هو tag مع ملاحظات وملفات اختيارية، ويستطيع GitHub توليد الملاحظات من الـ pull requests المدموجة.