EduFlow
Git و GitHub
⁦0%⁩

الوحدة 1 · نموذج Git

المناطق الثلاث: الـ Working Tree والـ Index والـ Repository

16 دقراءة 4 داملأ الفراغات

الدرس في لمحة

انقل التغييرات بوعي بين الـ working tree والـ staging area والـ repository، وافحص كل خطوة بـ status و diff، وقسّم العمل الفوضوي إلى commits مركّزة.

  1. 1ثلاثة أماكن قد يكون فيها عملك
  2. 2رؤية الفرق: status و diff بنوعيه
  3. 3تقسيم ملف واحد على اثنين من الـ commits
  4. 4ما الحجم المناسب للـ commit؟
  5. 5الحالة المختصرة، والتراجع

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

قضيت أمسية كاملة على موقعك الشخصي. أضفت شريط تنقّل إلى index.html، وأنشأت styles.css، وصحّحت خطأً إملائيًا في اسمك أثناء ذلك. هذه ثلاثة تغييرات لا علاقة لبعضها ببعض. لو سجّلتها معًا في commit واحد باسم “updates”، فلن تستطيع لاحقًا التراجع عن شريط التنقّل دون التراجع عن تصحيح الخطأ الإملائي أيضًا. يعطيك Git مكانًا ترتّب فيه التغييرات قبل أن تصبح جزءًا من السجلّ.

ثلاثة أماكن قد يكون فيها عملك

كل تغيير في مشروع Git يعيش في واحد من ثلاثة أماكن:

  • الـ working tree (مجلد العمل) هو الملفات على القرص، تلك التي يفتحها محرّرك. تغيّرها بحرية، و Git يراقب فقط.
  • الـ index، ويُسمّى أيضًا staging area (منطقة التجهيز)، هو الـ commit التالي قيد التجميع. الأمر git add ينسخ المحتوى الحالي للملف إليه.
  • الـ repository (المستودع) هو الـ commits المسجّلة بالفعل داخل .git. والأمر git commit يحوّل الـ index إلى commit جديد.
ثلاثة صناديق من اليسار إلى اليمين: الـ working tree، والـ index (منطقة التجهيز)، والـ repository. الأمر git add ينقل من الـ working tree إلى الـ index، و git commit من الـ index إلى الـ repository. وفي الأسفل، git restore --staged ينسخ من الـ repository عائدًا إلى الـ index، و git restore ينسخ من الـ index عائدًا إلى الـ working tree. Working tree الملفات على القرص Index الـ commit التالي Repository commits مسجّلة git add git commit git restore --staged git restore المتقطّع: نسخ عكسي. git restore يكتب فوق ملفك.
الأوامر تنقل المحتوى بين المناطق الثلاث

بعد الـ commit لا يُفرَّغ الـ index. بل يظل يحمل اللقطة الكاملة التي سجّلتها للتو، فيطابق آخر commit إلى أن تجهّز شيئًا جديدًا. لهذا فإن «التغييرات المجهّزة» تعني الفرق بين الـ index وآخر commit.

رؤية الفرق: status و diff بنوعيه

هذا عمل الأمسية كما يعرضه git status:

Text
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   index.html

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	styles.css

no changes added to commit (use "git add" and/or "git commit -a")

يخبرك git status أيّ الملفات تختلف. ولرؤية الأسطر نفسها استخدم git diff، وتذكّر أن هناك مقارنتين:

Terminal
git diff            # working tree vs index: what you haven't staged yet
git diff --staged   # index vs last commit: what the next commit will contain

الخيار --cached مرادف أقدم لـ --staged؛ وستراهما كليهما في الشروحات. اجعل تشغيل git diff --staged عادة قبل كل commit مباشرة. إنها اللحظة الأخيرة لتلاحظ console.log نسيته أو ملفًا لا ينتمي إلى هذا الـ commit.

تقسيم ملف واحد على اثنين من الـ commits

تصحيح الخطأ الإملائي وشريط التنقّل كلاهما في index.html. الأمر git add index.html سيجهّزهما معًا. جهّز تصحيح الخطأ وحده بدلًا من ذلك:

Terminal
git add -p index.html

يعرض Git كل كتلة متغيّرة، وتُسمّى hunk، ويسأل Stage this hunk [y,n,q,a,d,s,e,?]? (تعرض الإصدارات الأحدث حروفًا إضافية، والحرف ? يشرحها كلها). أجب بـ y على كتلة الخطأ الإملائي و n على كتلة شريط التنقّل (والحرف s يقسم الكتلة إن كانت كبيرة جدًا). ثم:

Terminal
git diff --staged          # only the typo fix
git commit -m "Fix spelling of name in header"
git add index.html styles.css
git commit -m "Add navigation bar with base styles"

اثنان من الـ commits، لكل منهما غرض واحد. ولاحقًا، إن احتجت إلى إزالة شريط التنقّل، تستطيع التراجع عن ذلك الـ commit وحده.

ما الحجم المناسب للـ commit؟

الـ commit الجيد يفعل شيئًا واحدًا تستطيع وصفه بجملة قصيرة دون كلمة «و». الرسالة “Fix spelling of name in header” تنجح في هذا الاختبار. أما “Add nav, fix typo, tweak colours” فتفشل، ويظهر الفشل لاحقًا: حين يتبيّن أن الألوان خاطئة، فإن التراجع عن ذلك الـ commit يزيل شريط التنقّل أيضًا ويعيد الخطأ الإملائي.

لا يوجد حدّ لعدد الأسطر. الـ commit الذي يعيد تسمية class في CSS عبر اثني عشر ملفًا يظل فكرة واحدة، وتقسيمه سيترك الموقع معطّلًا بين الخطوتين. اسعَ إلى commits يبقى المشروع بعدها وقبلها يعمل، وكل واحد منها خطوة تستطيع شرحها للمراجِع في نَفَس واحد. ستقدّر هذا في القسم الرابع، حين يصبح التراجع عن commit واحد أمرًا من سطر واحد بدل ساعات من العمل الجراحي الدقيق.

الحالة المختصرة، والتراجع

يضغط git status -s المعلومات نفسها في عمودين: الأيسر يقارن الـ index بآخر commit، والأيمن يقارن الـ working tree بالـ index.

Text
M  README.md
 M index.html
MM styles.css
?? projects.html

README.md مجهّز؛ و index.html فيه تغييرات غير مجهّزة؛ و styles.css فيه من الاثنين؛ و projects.html غير متتبَّع (untracked).

لإخراج ملف من الـ index دون أن تخسر تعديلاتك، استخدم git restore --staged styles.css. ولرمي التعديلات غير المجهّزة والعودة إلى نسخة الـ index، استخدم git restore styles.css. الأمر الثاني هو الوحيد في هذا الدرس الذي يُتلف عملًا: التغييرات التي لم تُجهَّز ولم تُسجَّل قط لا يمكن استرجاعها.

صرت قادرًا على تسجيل السجلّ الذي تقصده بالضبط. في الدرس التالي ستقرأ هذا السجلّ، وترى لماذا يسمّيه Git رسمًا بيانيًا (graph) لا قائمة.

أهم النقاط

  • الـ working tree هو ملفاتك، والـ index (منطقة التجهيز) هو الـ commit التالي قيد التجميع، والـ repository هو الـ commits المسجّلة بالفعل.
  • git diff يقارن الـ working tree بالـ index؛ و git diff --staged يقارن الـ index بآخر commit.
  • git add -p يجهّز جزءًا من الملف، فتتحوّل جلسة تعديل فوضوية واحدة إلى عدة commits مركّزة.
  • git restore --staged <file> يلغي التجهيز ويحتفظ بتعديلاتك؛ أما git restore <file> فيرمي تعديلاتك غير المجهّزة.
  • git commit -a يجهّز الملفات المتتبَّعة المعدّلة فقط؛ والملفات الجديدة كليًا ما زالت تحتاج git add.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

جهّزت index.html، ثم عدّلته مرة أخرى. يعرض git diff التعديل الثاني فقط. لماذا؟

السؤال 2 من 4

شغّلت git add styles.css لكنك تريده في الـ commit القادم لا في هذا. أيّ أمر يحتفظ بتعديلاتك ويلغي تجهيز الملف فقط؟

السؤال 3 من 4

أنشأت projects.html وعدّلت index.html، ثم شغّلت git commit -am "Add projects page". ماذا احتوى الـ commit؟

السؤال 4 من 4

في ناتج git status -s، ماذا يخبرك السطر MM index.html؟

تدريب

املأ الفراغات

جهّز عن قصد

أكمل الجلسة. تجهّز جزءًا فقط من index.html (تصحيح الخطأ الإملائي)، وتتحقّق بالضبط مما سيدخل في الـ commit، وتسجّله، ثم تجهّز عمل شريط التنقّل لكنك تُخرج styles.css من الـ index دون أن تخسر تعديلاتك.

git status git add index.html # stage only the typo-fix hunk git diff # check what the next commit contains git commit -m "Fix spelling of name in header" git add index.html styles.css git restore styles.css # oops: unstage it, keep the edits git commit -m "Add navigation bar"