أساسيات Git للمختبِرين
Git نظام للتحكم في الإصدارات (version control): يسجّل تاريخ المشروع سلسلةً من اللقطات تُسمّى الإيداعات (commits)، ولكل إيداع معرّف فريد ومؤلف وتاريخ ورسالة ورابط إلى الإيداع الذي قبله. فعندما يصلح مطوّر تقريب ضريبة القيمة المضافة في صفحة الدفع ويودع التغيير باسم 3f9c2ab، يصبح ذلك الإيداع نقطة دائمة في التاريخ: يستطيع أي شخص أن يرى الأسطر التي تغيّرت ومن غيّرها ومتى، وأن يختبر تلك النسخة بالضبط.
وبالنسبة إلى المختبِر، لا يتعلق Git بكتابة الشيفرة بقدر ما يتعلق بمعرفة ما تختبره بالضبط: أي نسخة، وأي تغيير، وما الذي لمسه هذا التغيير أيضاً.
لماذا يهم
«أي بناء (build) اختبرت؟» سؤال يجيب عنه Git بدقة. فمن دون معرّف الإيداع يصعب إعادة إنتاج الإخفاق، ولا يستطيع أحد أن يثبت أن إعادة الاختبار جرت على النسخة التي فيها الإصلاح. أما عبارة «يفشل على main عند 3f9c2ab» فيستطيع أي عضو في الفريق إعادة إنتاجها.
ويُظهر Git أيضاً ما الذي تغيّر: فالفروقات (diff) منذ آخر نسخة مختبَرة مدخل مباشر لاختيار اختبارات الانحدار. كما أن الاختبارات الآلية وبيانات الاختبار وملفات خط الأنابيب تعيش في المستودع نفسه مع شيفرة المنتج، فصيانتها تعني أن تودع وتنشئ الفروع وتدمج كما يفعل المطور.
المستودع والإيداع والأماكن الثلاثة التي يمر بها التغيير
المستودع (repository) مجلد المشروع مع تاريخه الكامل، ويحفظه Git في مجلد مخفي اسمه .git. أما النسخة المشتركة للفريق، أي المستودع البعيد (remote) الذي يُسمّى عادةً origin، فتوجد على خادم، والأمر git clone ينسخها إلى جهازك مع التاريخ كله. وبعد ذلك ينزّل git fetch الإيداعات الجديدة ويسجّل المواضع التي صارت تشير إليها فروع المستودع البعيد بأسماء مثل origin/main دون أن يمس ملفاتك، أما git pull فيحدّث فرعك الحالي أيضاً، ويرسل git push إيداعاتك أنت إلى origin.
يمر التغيير بثلاثة أماكن: شجرة العمل (working tree) وهي الملفات التي تعدّلها، ومنطقة التجهيز (staging area) أو الفهرس (index) وفيها التغييرات التي تختارها بالأمر git add، ثم التاريخ حيث يسجّل git commit لقطة لما جُهّز. ويسمّي Git كل إيداع ببصمة (hash)، وهي قيمة ثابتة الطول تُحسب من محتوى الإيداع وتاريخه: 40 محرفاً بالنظام السداسي العشري (بخوارزمية SHA-1 في معظم المستودعات)، وتُعرض عادةً مختصرةً إلى أول سبعة محارف أو أكثر مثل 3f9c2ab. وإذا تغيّر محرف واحد تغيّر المعرّف، ولذلك يدل معرّف الإيداع على نسخة واحدة بالضبط. وتُظهر أداة «مولّد SHA-1» هذا الأثر على أي نص، لكن Git يحسب بصمة الإيداع بصيغته الداخلية الخاصة، فلن تحصل بها على معرّف إيداع.
$ git clone https://git.example.com/shop/web.git # the repository and its history
$ cd web
$ git fetch # later: get new commits from origin; files untouched
$ git pull # fetch, then bring your current branch up to date
$ git status # what is modified, staged or untracked
$ git add tests/checkout/vat.spec.ts
$ git commit -m "Add VAT test for a total ending in .005"
$ git push # send your new commits to originالفروع وHEAD والدمج
الفرع (branch) اسم متحرك يشير إلى إيداع واحد، وكل إيداع جديد على الفرع يحرّك الاسم إلى الأمام. ويحمل الفرع main (وفي المستودعات الأقدم غالباً master) عادةً النسخة المدمجة من المنتج، وينشئ المطورون فرعاً قصير العمر لكل تغيير، مثل fix/vat-rounding، حتى لا يزعج العمل غير المكتمل أحداً. وHEAD هو ما سحبته (checked out) حالياً، وهو عادةً فرع.
الدمج (merge) يُدخل إيداعات فرع في فرع آخر. فإذا لم يتحرك الفرع الهدف منذ بدء الفرع، يكتفي Git بتحريك اسمه إلى الأمام (fast-forward)؛ وإذا كان لدى الطرفين إيداعات جديدة، أنشأ إيداع دمج له أبوان. وإذا غيّر الطرفان الأسطر نفسها، توقف Git عند تعارض دمج (merge conflict) وكتب شخصٌ النتيجة. وحتى الدمج النظيف يجمع تغييرات لم تُشغَّل معاً من قبل، لذا يستحق البناء المدمج اختباراً خاصاً به. أما استراتيجيات التفريع وطلبات الدمج (pull requests) فموضوع الدرس التالي.
في مخرجات git log --graph تمثّل كل * إيداعاً، وتقود الخطوط إلى آبائه، وتبيّن الأسماء بين القوسين أين تشير الفروع والوسوم (tags) وHEAD.
fix/vat-rounding يبدأ من الإصدار v2.3.0 ويتلقى إيداعاً واحداً بينما يتلقى main إيداعين، ودمجه يُنشئ إيداع الدمج 9e41d07 ذا الأبوين.mainالمنتج المدمجfix/vat-roundingتغيير واحد بمعزل عن غيره
- 1
mainداخليًا: وسم الإصدارv2.3.0على1d2e3f4آخر نسخة اختبرها المختبِر - 2 من
mainإلىfix/vat-rounding: إنشاء الفرع عند الإيداع نفسهgit switch -c fix/vat-rounding - 3
mainداخليًا: الإيداع5b0a9f4: حد أدنى للطلب 50.00 ريالاً يواصل الزملاء الإيداع فيmain - 4
mainداخليًا: الإيداعc7d2e18: تسميات الفاتورة العربية - 5
fix/vat-roundingداخليًا: الإيداع3f9c2ab: إصلاح تقريب الضريبة لا يوجد حتى الآن إلا في هذا الفرع - 6 من
fix/vat-roundingإلىmain: الدمج: إيداع الدمج9e41d07له أبوان:c7d2e18و3f9c2abgit merge fix/vat-rounding - 7
mainداخليًا: المختبِر يسرد الجديد أربعة إيداعات منذv2.3.0: نطاق اختبار الانحدارgit log --oneline v2.3.0..main
الزمن يسير من الأعلى إلى الأسفل، وكل مسار اسم فرع يتقدّم مع كل إيداع جديد.
$ git switch -c fix/vat-rounding # new branch at the current commit, switch to it
$ git commit -am "Fix VAT rounding for totals ending in .005" # -a stages edited files
$ git switch main
$ git pull # fast-forward: two new commits from colleagues
$ git merge fix/vat-rounding # both sides moved on: Git makes a merge commit
$ git log --oneline --graph -5
* 9e41d07 (HEAD -> main) Merge branch 'fix/vat-rounding' into main
|\
| * 3f9c2ab (fix/vat-rounding) Fix VAT rounding for totals ending in .005
* | c7d2e18 (origin/main) Add Arabic labels to the invoice PDF
* | 5b0a9f4 Update minimum order total to 50.00 SAR
|/
* 1d2e3f4 (tag: v2.3.0) Release 2.3.0قراءة التاريخ بالأوامر log وshow وdiff
يعرض git log الإيداعات من الأحدث إلى الأقدم، ويعرض git show إيداعاً واحداً مع تغييراته، ويقارن git diff بين أي نسختين. والوسم (tag) اسم ثابت لإيداع واحد، وغالباً ما يكون إصداراً مثل v2.3.0.
في الفروقات أدناه يسمّي --- و+++ الملف القديم والملف الجديد، والأسطر التي تبدأ بـ- حُذفت، والتي تبدأ بـ+ أُضيفت، ويعني @@ -9,5 +9,5 @@ أن المقطع يبدأ من السطر 9 ويمتد خمسة أسطر في النسختين، أما النص الذي يلي @@ الثانية فمجرد سطر سابق من الملف يُعرض للتوجيه.
git log --oneline v2.3.0..main: كل ما فيmainوليس في الإصدارv2.3.0.git log --oneline -- src/checkout/: الإيداعات التي لمست مجلد الدفع فقط.git diff --stat v2.3.0 main: الملفات التي تغيّرت وعدد أسطرها بين نسختين.git tag --contains 3f9c2ab: الإصدارات التي تتضمن إصلاحاً معيناً.
$ git diff v2.3.0 main -- src/checkout/vat.ts
diff --git a/src/checkout/vat.ts b/src/checkout/vat.ts
index 4b1e2c0..9d7a3f1 100644
--- a/src/checkout/vat.ts
+++ b/src/checkout/vat.ts
@@ -9,5 +9,5 @@ import { roundHalfUp } from './money';
// VAT rate in this example: 15 %
export function vatFor(net: number): number {
const rate = 0.15;
- return Math.round(net * rate * 100) / 100;
+ return roundHalfUp(net * rate, 2);
}مثال تطبيقي: ما الذي تغيّر منذ آخر إصدار
اختبرت الإصدار v2.3.0 الأسبوع الماضي، واليوم طُلب منك اختبار انحدار على أحدث نسخة من main. وقبل أن تفتح التطبيق تسأل Git عمّا تغيّر، والأوامر ومخرجاتها في نهاية هذا القسم. اقرأها ملفاً ملفاً:
vat.ts: تغيّر سطر واحد في تقريب ضريبة القيمة المضافة. اختبر مبالغ تنتهي ضريبتها بنصف هللة، مثل سعر صافٍ قدره 1.10 ريال (الضريبة 0.165). ويبيّنgit grepأن الإجماليات والمبالغ المستردة تستدعيvatForأيضاً، فيدخل الاسترداد في النطاق.min-order.ts: أصبح الحد الأدنى للطلب 50.00 ريالاً. اختبر 49.99 و50.00 كما في تحليل القيم الحدّية، وإن لم تذكر أي تذكرة أو ملاحظات إصدار هذا التغيير فاسأل قبل الاختبار.labels.ar.json: تسميات عربية جديدة للفاتورة. افحص فاتورة PDF العربية واتجاهها من اليمين إلى اليسار.vat.spec.ts: اختبارات وحدة جديدة. القيم التي تغطيها تحتاج جهداً يدوياً أقل، والقيم التي تفوتها تدخل قائمتك.- اكتب «اختبار انحدار على
mainعند9e41d07، والتغييرات منذv2.3.0» في تقرير الاختبار وفي كل تقرير خطأ.
$ git fetch origin
$ git log --oneline v2.3.0..origin/main
9e41d07 (origin/main) Merge branch 'fix/vat-rounding' into main
3f9c2ab Fix VAT rounding for totals ending in .005
c7d2e18 Add Arabic labels to the invoice PDF
5b0a9f4 Update minimum order total to 50.00 SAR
$ git diff --stat v2.3.0 origin/main
src/checkout/min-order.ts | 4 ++--
src/checkout/vat.ts | 2 +-
src/invoice/labels.ar.json | 18 ++++++++++++++++++
tests/checkout/vat.spec.ts | 21 +++++++++++++++++++++
4 files changed, 42 insertions(+), 3 deletions(-)
$ git grep -n "vatFor(" origin/main -- src
origin/main:src/checkout/total.ts:27: const vat = vatFor(net);
origin/main:src/checkout/vat.ts:10:export function vatFor(net: number): number {
origin/main:src/refunds/refund.ts:41: return amount + vatFor(amount);أخطاء شائعة
- الإبلاغ عن الخطأ على «أحدث بناء» بدلاً من معرّف إيداع أو وسم: فلا يستطيع أحد إعادة إنتاج الإخفاق ولا إثبات أن إعادة الاختبار جرت على الإصلاح.
- اختبار نسخة قديمة: فالأمر
git statusلا يعرف حالةoriginإلا كما كانت عند آخرgit fetch. - الوثوق برسائل الإيداع دون قراءة الفروقات: فإيداع بعنوان «refactor» قد يغيّر قاعدة عمل.
- إيداع الأسرار وملفات
.envوتقارير الاختبار ولقطات الشاشة. استخدم.gitignore؛ فالسر المحذوف لاحقاً يبقى في التاريخ، لذا أبلغ عنه فوراً كي يُلغى. - إجراء إيداعات كبيرة برسائل مثل «fix»: فلا يعود التاريخ يخبر أحداً بما تغيّر ولماذا، ولا يمكن العثور على تغيير بعينه أو التراجع عنه وحده.
من منظور ضمان الجودة
يستخدم المختبِر جزءاً صغيراً من Git كل يوم: يسجّل النسخة المختبَرة بالضبط، ويقرأ السجل والفروقات منذ آخر نسخة مختبَرة ليختار اختبارات الانحدار، ويسحب إيداعاً محدداً ليعيد إنتاج إخفاق، ويحفظ الاختبارات الآلية في المستودع حيث تبدأ خطوط CI عند أحداث Git مثل الدفع (push) أو الدمج. ويسمّي منهج ISTQB للمستوى التأسيسي هذا الانضباط إدارة التهيئة (configuration management): تُعرَّف عناصر الاختبار ومواد الاختبار (testware) تعريفاً فريداً وتخضع للتحكم في الإصدارات.
اطلب الإيداع أو طلب الدمج الذي يصلح كل عيب واربطه بسجل العيب، وقبل اختبار التأكيد (confirmation testing) تحقّق من أن الإصلاح موجود في البناء الذي بين يديك. ولا تحتاج إلى فهم كل سطر في الفروقات: فأسماء الملفات والدوال وحجم التغيير تكفي لتسأل «ما الذي يستخدم هذا أيضاً؟»، وهو السؤال الذي يكشف الانحدار.
تمرين عملي
اقرأ تاريخ إصدار وخطّط لإعادة الاختبار
آخر إصدار اختبرته من تطبيق متجر هو v1.8.0. باستخدام المخرجات أدناه، حدّد الإيداعات الجديدة والفرع وإيداع الدمج، واكتب المجالات التي يجب اختبارها، وقرّر كيف ستحدّد النسخة المختبَرة.
$ git log --oneline --graph v1.8.0..main
* a41f9c0 (HEAD -> main) Merge branch 'feature/saved-cards' into main
|\
| * 7be2d15 Mask card number except the last 4 digits
| * 0c93e6a Add saved cards page
* | e5d8b72 Fix account lockout after 5 failed logins
|/
* 52aa1f3 Change password reset link expiry to 30 minutes- اقرأ الرسم من الأسفل إلى الأعلى: أين بدأ الفرع، وأين دُمج؟
- جمّع الإيداعات الجديدة حسب مجال المنتج.
- اكتب فكرتين أو ثلاثاً للاختبار في كل مجال، مستخدماً تقنيات الدروس السابقة.
- اكتب سطر النسخة لتقريرك وسؤالاً واحداً للفريق.
إظهار الإجابة النموذجية
هناك خمسة إيداعات جديدة. بدأ الفرع feature/saved-cards عند 52aa1f3 ويضم 0c93e6a و7be2d15، وفي الأثناء أُودع e5d8b72 على main.
a41f9c0 هو إيداع الدمج: أبوه الأول e5d8b72 (رأس main السابق)، وأبوه الثاني 7be2d15 (رأس الفرع). وربما لم يُختبر الخطّان معاً قط، لذا يحتاج البناء المدمج إلى جولة اختبار خاصة به.
المصادقة: روابط إعادة تعيين كلمة المرور قبل 30 دقيقة بقليل وبعدها بقليل، ورابط يُستخدم مرتين؛ و4 و5 و6 محاولات دخول فاشلة. المدفوعات: إضافة البطاقات المحفوظة وعرضها، مع ظهور آخر 4 أرقام فقط في الصفحة واستجابات API والرسائل البريدية والسجلات.
سطر النسخة: «اختبار انحدار على main عند a41f9c0، والتغييرات منذ v1.8.0». السؤال: هل جاءت مدة الصلاحية البالغة 30 دقيقة من تذكرة، وهل تنطبق على الروابط المرسلة قبل الإصدار؟
أسئلة شائعة
هل أحتاج إلى Git إذا كنت أختبر يدوياً فقط؟
تحتاج إلى جانب القراءة منه: معرّفات الإيداع والوسوم والسجل والفروقات، لتعرف أي نسخة اختبرت وما الذي تغيّر فيها. وخدمات الاستضافة تعرض التاريخ نفسه في المتصفح، فيمكنك البدء منها. أما كتابة الإيداعات وحل التعارضات فتصبح ضرورية حين تصون اختبارات آلية.
ما الفرق بين Git وGitHub؟
Git أداة التحكم في الإصدارات، تعمل على جهازك ومعظم أوامرها لا تحتاج إلى شبكة. أما GitHub وGitLab وBitbucket فخدمات تستضيف المستودعات البعيدة وتضيف فوق Git طلبات الدمج وتتبّع المهام وخطوط CI.
ما الفرق بين git fetch وgit pull؟
git fetch ينزّل الإيداعات الجديدة ويحدّث فروع التتبع البعيدة مثل origin/main، لكنه لا يمس ملفاتك ولا فرعك. أما git pull فينفّذ fetch ثم يحدّث فرعك الحالي: إن لم تكن لديك إيداعات جديدة خاصة بك فإنه يكتفي بتحريك فرعك إلى الأمام (fast-forward)، وإن كانت لدى الطرفين إيداعات جديدة فلا بد من دمجها أو إعادة التأسيس (rebase)، أي إعادة تطبيق إيداعاتك فوق الإيداعات الجديدة، والإصدارات الحديثة من Git تتوقف وتطلب منك الاختيار بـ--no-rebase أو --rebase أو بالإعداد pull.rebase.
هل من الآمن سحب إيداع قديم لإعادة إنتاج خطأ؟
نعم. الأمر git checkout 3f9c2ab (أو git switch --detach 3f9c2ab) يضع تلك النسخة في شجرة العمل بحالة «detached HEAD»: يمكنك بناؤها واختبارها، ثم يعيدك git switch main. أودع تغييراتك أولاً أو ضعها جانباً بالأمر git stash، لأن Git يرفض التبديل إذا كانت ستُستبدل.
المراجع
- Reference — Gitالمرجع الرسمي لكل أوامر Git وخياراتها، مجمّعةً حسب المهمة — الإعداد والتفريع والمشاركة وتطبيق الرقع والفحص وتتبّع الأخطاء.
- Pro Git, 2nd Edition (Scott Chacon and Ben Straub)كتاب Pro Git المتاح للقراءة مجاناً على الإنترنت: أساسيات Git، والتفريع والدمج، وسير العمل الموزّع، وكيف يخزّن Git بياناته.
- ISTQB Certified Tester Foundation Level (CTFL) v4.0المنهج التأسيسي لاختبار البرمجيات: مستويات الاختبار وأنواعه وتقنيات تصميم الاختبارات وإدارة الاختبار والأدوات.
تدرّب بأدوات متقن
قارن نصّين سطراً بسطر أو كلمةً بكلمة مع إبراز الاختلافات.
ولّد سيناريوهات اختبار الانحدار من وصف التغيير وقائمة الوحدات المتأثرة والمرتبطة.
توليد تجزئات SHA-1 للنصوص باستخدام واجهة WebCrypto في المتصفح.
للتعمّق أكثر
تقدّمك في هذا الموضوع
سجّل الدخول لتتابع تقدّمك
علّم الموضوعات مكتملة، وتابع من حيث توقفت، وافتح امتحانات التخصص.