انتقال للمقال
وقت القراءة: ≈ 20 دقيقة (بمعدل فنجان واحد من القهوة 😊)

أساسيات الـ Git لتتبع التغييرات في المشاريع

السلام عليكم ورحمة الله وبركاته

يمكنك متابعة السلسلة بالترتيب أو الانتقال مباشرة إلى أي مقال:


المقدمة

اليوم لدينا مقالة دسمة إلى حد ما، سأتكلم في هذه المقالة عن الـ Git وكيف يعمل وكيف نستفيد منه ونستخدمه وما أهم الأوامر الخاصة به
وكيف يفيدنا في تنظيم مشاريعنا وتنظيم طريق العمل ضمن فريق

في هذه المقالة سأركز على الـ Git في بيئة عمل Local أي على جهازك الشخصي
وسأشرح الأساسيات التي تحتاجها لكي تبدأ في استخدامه

ثم في مقالة أخرى سنتكلم عن أوامر أكثر مثل git reset و git checkout و git stash وغيرها

ويمكنكم قراءتها من هنا تكملة أوامر الـ Git والتحكم بالـ HEAD

ثم في مقالة أخرى سنتكلم عن مفهوم الـ Branch

ويمكنكم قراءتها من هنا Git Branches آلة السفر عبر الأبعاد

ثم في مقالة أخرى سنتطرق لجزء الـ Remote الخاص بالـ Git وكيف نتعامل مع GitHub وكل تلك الأمور إن شاء الله

يمكنكم قراءتها من هنا التعامل مع Remote Repository وموقع GitHub

ما هو الـ Git

الـ Git هو باختصار آلة السفر بين الزمن والأبعاد ... أقصد أنه أشهر Version Control System
بمعنى أنه نظام متكامل تم إنشاؤه لتنظيم وإدارة المشروعات بسلاسة ويسجل كل التغيرات والإضافات التي حدثت لمشروع على مر الزمن

بعض من أهم ما يقدمه:

  • يتابع تاريخ المشروع بالكامل عبر الزمن، بما في ذلك على سبيل المثال الإضافات والتعديلات وما الذي تم حذفه
    والإشارة إلى من قام بالتغير ومتى قام به
  • يمكن أيضا استخدام Git كآلة للسفر عبر الزمن، حيث يمكنك العودة إلى نسخة قديمة من مشروعك في أي وقت ومقارنة التعديلات السابقة بالحالية
  • من بين أهم مزاياه أيضا أنه يمكنك استنساخ المشروع لعدة نسخ، وكل نسخة تطور فيها وتعدل وتفعل ما تريده دون أن تأثر على نسخة المشروع الأساسية
  • أو تقسم العمل ضمن الفريق حيث يمكن لكل عضو العمل على نسخته من الكود في فرع مختلف بشكل مستقل عن باقي الفريق
    (... همس: قلت لك أنه جهاز سفر عبر الأبعاد)

سنتكلم عن كل هذه التفاصيل وأكثر

كيف يتعامل الـ Git مع مشروعك ؟

هناك عدة مراحل يتخذها الـ Git للتنقل الحالات المختلفة لمشروعك والتعديلات
وهذه المراحل مهمة جدًا في أن تستوعبها وتفهمها جيدًا لأنها ستكون أساس كل شيء سنشرحه في باقي هذه المقالة

ملحوظة: أول شيء عليك معرفته هو أن الـ Git ينشيء مجلد يدعى .git داخل المشروع الخاص بك
وهو المنزل الخاص بـ Git الذي يضم كل شيء متعلق به
بما في ذلك الـ Local Repository والـ Staging Area و Stash وكل شيء متعلق ويستخدمه الـ Git

Working Directory

الـ Working Directory وأيضًا يطلق عليه الـ Working Tree
هو المجلد الأساسي الذي يحتوي على ملفات المشروع على جهازك

Local Repository

الـ Local Repository هو مستودع يستخدمه الـ Git ليحتفظ ويتابع التعديلات الموجودة في الـ Working Directory الخاص بك على جهازك
ويطلق عليه عدة مسميات مثل Git Repository أو Git Directory أو Git History

Upstream Repository

الـ Upstream Repository أو الـ Remote Repository
هو كالـ Local Repository لكنه نسخة رئيسية من المشروع يتم استضافتها في مكان ما على الانترنت مثل GitHub أو GitLab أو غيرهم كثير
ويسهل العمل مع فريق من أماكن مختلفة ويقدم مميزات كثيرة تساعد على ها وتحقيق اقصى استفادة ممكنة في العمل ضمن فريق
بمعنى أن كل عضو لديه نسخته من المشروع ويعدل في الـ Local Repository الخاص به ثم في النهاية يرفع تلك التعديلات على الـ Remote Repository ليتشاركها مع الجميع وكل الفريق يتابع آخر التعديلات التي قام بها كل عضو

Staging Area

الـ Staging Area وتسمى أيضًا بالـ Index أو Cache هي مرحلة وسيطة ما بين الـ Working Directory والـ Local Repository
تستخدم لوضع التعديلات التي قمنا بها في الـ Working Directory قبل نقلها إلى الـ Local Repository
أو العكس لوضع التعديلات التي ترغب في التراجع عنها من الـ Local Repository قبل إزالتها من الـ Working Directory

هذه المنطقة الوسيطة وجدت لتجنب التعديل والتغير المباشر ما بين الـ Working Directory و الـ Local Repository
لكي يتم مراجعتها جيدًا والتأكد من كل شيء قبل تنفيذ العملية التي نريدها سواء إضافة أو تعديل أو حذف
ومن المهم دائمًا وجود مرحلة تأكيدية كتلك لتجنب الأخطاء الغير مقصودة أو الاستعجالية التي تحدث عندما نفذ التعديل بشكل مباشر

وأيضًا يحتفظ بالملفات الـ Tracked ليتابعها ويقارنها مع النسخة التي في الـ Working Directory ليتأكد هل تم تعديلها أم لا

Stash

الـ Stash هو مكان يستخدم لحفظ التعديلات التي قمت بها بشكل مؤقت، ثم يمكنك العمل على شيء آخر أو أن تنتقل
إلى branch آخر، ثم بعد انتهائك يمكنك أن تعود وتستحضر التعديلات المحفوظة التي قمت بها من الـ Stash في أي وقت

كيف يتعامل Git مع ملفات المشروع ؟

نستطيع أن نقول أن Git يصنف الملفات لعدة حالات ليسهل عليه التعامل معها ويتابعها ويراقب التغيرات

Untracked Files

الـ Untracked Files هي الملفات التي لا يتم متابعتها من قبل Git
بمعنى أنها ملفات موجودة في الـ Working Directory ولكن Git لا يعرف شيئًا عنها ولم يتخذ أي إجراء تجاهها من قبل
أي أنها لم تُنقل إلى الـ Staging من قبل أو تم حذفها من الـ Staging والـ Git لم يعد يتابعها

Tracked Files

الـ Tracked Files هي الملفات التي أصبح Git يدرك وجودها ويتابع أي تغير فيها
ويملك نسخة منها في الـ Staging ليتابعها

Modified Files

هي الملفات التي كان Git يتابعها أي أنها Tracked بالفعل لكن حصل لها تعديل ولم تنقل إلى مرحلة الـ Staging بعد
بمعنى أن نسختها التي في الـ Working Directory مختلفة عن نسختها التي يتم متابعتها في الـ Staging

Staged Files

هي الملفات التي كان Git يتابعها أي أنها Tracked بالفعل وحصل لها تعديل ثم نُقلت إلى مرحلة الـ Staging
أي أن نسختها التي في الـ Staging مختلفة عن نسختها التي في الـ Local Repository

أهم أوامر الـ Git

حسنًا سنتخذ مثال وهمي بسيط وسنشرح أهم الأوامر الخاصة بـ Git عن طريق المثال
حسنًا لنتخيل أننا لدينا مشروع لمدونة جميلة وهذا المشروع حاليا فيه ملف واحد يمثل مقالة واحدة

> ls
article_1.txt

التعريف بنفسك

أول شيء نفعله وهو أن تعرف نفسك لـ Git
لذا نستخدم git config --global user.email "your@email.com" و git config --global user.name "your name"
لتسجيل اسمك وبريدك الإلكتروني في Git على مستوى جهازك الشخصي

أما اذا اردت على مستوى المشروع الحالي فيمكنك ازالة --global

> git config --global user.email "eltabaraniahmed@gmail.com"
> git config --global user.name "AhmedEl-Tabarani"

git init

نستخدم git init لمرة واحدة فقط داخل المجلد الذي فيه المشروع أي الـ Working Directory لنخبر الـ Git
أن يبدأ بإنشاء مجلد الـ .git الذي يضم كل شيء متعلق به
بما في ذلك الـ Local Repository والـ Staging Area و Stash
يبدأ في مراقبة ومتابعة أي تعديلات في هذا الـ Working Directory

> git init
Initialized empty Git repository in blog/.git/

لاحظ أنه يخبرنا أنه أنشيء Git Repository وهو مجلد يدعى .git وهو المنزل الخاص بـ Git الذي الذي يضم كل شيء متعلق به كما قلنا
وهو مجلد خفي لكن يمكنك ان تراه وتتأكد من وجوده عن طريق أمر بسيط

> ls --all
./  ../  .git/  article_1.txt

ملحوظة: وعندما نقوم بعمل git init لاول مرة لمشروعنا يبدأ Git بعمل branch فارغ يدعى main لا يحتوي على أي commit بعد

git status

نستخدم git status لمعرفة حالة المشروع والملفات التي لدينا
هل تم تعديل الملفات أم لا ؟ هل يوجد ملفات جديدةUntracked أم لا
أو هل هناك ملفات نُقلت للـ Staging أم لا ... إلخ

وأيضا دائمًا ما يساعدك على اقتراح لك بعض الأوامر التي يمكنك أن تقوم بها في الحالة التي أنت فيها

> git status
On branch main

No commits yet

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

nothing added to commit but untracked files present (use "git add" to track)

لاحظ أن git status أخبرنا بالكثير من المعلومات، بما في ذلك:

  • أننا في الـ branch الأساسي main الذي ينشئه Git لنا ليضم كل الـ commit الخاصة بمشروعنا
  • أننا لا نملك أي commit بعد وهذا منطقي لأننا لم نفعل شيء بعد
  • أن هناك ملف في الـ Working Directory يسمى article_1.txt من ضمن الـ Untracked Files
    و Git لا يعرف عنه أي شيء
  • أيضًا بعض النصائح حول كيفية التصرف، مثل استخدام git add لتحويل الملف إلى Tracked من قبل Git وأيضًا لنقل الملف إلى مرحلة الـ Staging

git add file-name

نستخدم git add عندما نريد نقل التعديلات من الـ Working Directory إلى مرحلة الـ Staging
ويحول الملفات من حالة Untracked إلى Tracked

يمكنك git add ثم اسم الملف أو اسم المجلد الذي تريد نقله إلى مرحلة الـ Staging
أو يمكنك القيام بكتابة git add ثم . أو * لنقل كل التعديلات

> git add article_1.txt

الآن، بعد إضافة الملف article_1.txt إلى مرحلة الـ Staging، يمكننا أن نستخدم git status مجددًا إذا اردنا لكي نرى حالة الملفات الآن

> git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   article_1.txt

لاحظ أنه لم يعد يقول لنا أن الملف article_1.txt انه Untracked
بل يخبرنا أنه الآن في مرحلة الـ Staging وأنه اصبح جاهزًا لكي نقوم بعمل commit لننقله إلى الـ Local Repository
ويقول استخدم git rm --cached <file> لك إن أردنا حذف الملف من مرحلة الـ Staging وإرجاعه مجددا لحالة الـ Untracked

git commit -m nice-message

نستخدم git commit عندما نريد نقل التعديلات من مرحلة الـ Staging إلى الـ Local Repository
وعندما نقوم بعمل commit فهكذا كأننا نقوم بحفظ نسخة جديدة من المشروع والتعديلات التي حصلت فيه

وقد تسمع أن commit ينشيء snapshot لمشروع أي نسخة من المشروع
ويمكننا القول أن الـ Local Repository هو مجموعة من الـ snapshot التي تم حفظها من المشروع

ولاحظ أن git commit تقوم بنقل كل الملفات والتغيرات المتواجدة في مرحلة الـ Staging كحزمة واحدة إلى الـ Local Repository في commit واحد فقط

بمعنى أن commit واحد قد يضم أكثر من ملف وتعديل

ونستخدم -m لكتابة رسالة توضح التغييرات التي تمت في هذا الـ commit
لتساعدك أنت والفريق الذي معك بتبع تاريخ كل التغيرات التي حصلت في المشروع فيما بعد

ويفضل أن تكون الرسالة مختصرة ومعبرة وغالبًا ما تتفق أنت وباقي الفريق على صيغة معينة لكتابة تلك الرسائل التوضحية

> git commit -m "add new article to the blog"
[main (root-commit) 4032898] add new article to the blog
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 article_1.txt

لاحظ أن Git يخبرنا ببعض المعلومات الجميلة منها

  • الـ commit هذا هو الـ root-commit لفرع الرئيسي للمشروع وهو branch الـ main
  • يخبرنا بعدد الملفات التي حدث فيها التغير، وفي حالتنا ملف واحد فقط
  • يخبرنا بعدد الاسطر التي اضيفت والتي حذفت، وبما ان الملف الذي اضفناه كان فارغًا فلا يوجد اسطر

وأمر لم يخبرنا به وهو أنه أصبح لدينا مؤشر يدعى HEAD ويؤشر على آخر commit تم اضافته إلى الـ main
وسنتحدث عن هذا بالتفصيل لاحقًا في هذه المقالة

ملحوظة: الـ HEAD يتواجد داخل الـ Local Repository بالطبع، والـ commit الذي يشاور عليه هو ما نراه في الـ Working Directory وسنفهم معنى هذا لاحقًا

حسنًا لنقم بعمل git status مجددًا لكي نرى حالة الملفات الآن

> git status
On branch main
nothing to commit, working tree clean

الآن، يخبرنا Git أنه لا توجد تغييرات جديدة
وبالتالي لا توجد أي ملفات تحتاج إلى الانتقال إلى مرحلة الـ Staging أو عمل لها commit ونقلها إلى الـ Local Repository
ولذا يقول لك أن الـ Working Tree أي الـ Working Directory الخاص بالمشروع نظيف ولا يحتاج إلى أي شيء

git restore file-name

نستخدم git restore ثم اسم الملف عندما يكون الملف حالته Tracked بالنسبة للـ Git لكن تم التعديل عليه
أي أن نسخته التي في الـ Working Directory مختلفة عن نسخته التي في الـ Staging
ونريد التراجع عن هذا التعديل وإرجاع الملف لحالته الأصلية التي كان عليها

ما يقوم به git restore حقًا هو أنه يأخذ نسخة الملف التي في الـ Staging ويستبدلها مع الملف الذي في الـ Working Directory

الـ Staging هو أيضًا يحتفظ بنسخة بالملفات التي يتابعها وعن طريقها يستطيع معرفة إن حدث تعديل أم
بالتالي إن كان هناك ملف تم تعديله في الـ Working Directory فنستطيع عن طريق استخدام git restore استبدالها لترجع وتصبح طبق الأصل لنسختها التي في الـ Staging كما كانت
ونكون قد تخلصنا من التعديلات التي حدثت للملف في الـ Working Directory

لنرى مثال توضيحي، أولًا لنعدل في ملف المقالة article_1.txt ونضيف أي شيء

> echo "In this article we will prove that git is a time machine!" > article_1.txt

بعد ما اضفنا سطر وعدلنا في article_1.txt، لنقم بعمل git status لكي نرى حالة الملف

> git status
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:   article_1.txt

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

أنظر كيف يقوم الأمر git status بتوضيح كل شيء لك ويساعدك على اتخاذ القرارات
يقول لك هنا:

  • أنه لا يوجد ملفات حالتها Untracked لكن يوجد ملف Tracked تم التعديل عليه
    بمعنى أن نسخته في الـ Working Directory مختلفة عن نسخته في الـ Staging
  • ويقول لك أنك يمكنك أن تضيف هذا الملف إلى مرحلة الـ Staging عن طريق git add
  • أو يمكنك التراجع عن التعديل وجعل الملف يرجع لحالته الأصلية التي كان عليها عن طريق git restore

لذا لكي نخبره أننا نريد التراجع عن التعديل فسنقول له git restore article_1.txt

> git restore article_1.txt

هكذا سيقوم Git بالذهاب إلى الـ Staging واحضار نسخة الملف article_1.txt المتواجده فيه ويستبدلها
بالملف الذي في الـ Working Directory

git restore --staged file-name

هذا هو نفس الأمر السابق لكن مع زيادة --staged
والفرق هنا ان الملف الذي تم التعديل عليه دخل إلى مرحلة الـ Staging بالفعل عن طريق git add
والآن نريد أن نخرجه فقط من مرحلة الـ Staging دون أن نتراجع عن التعديلات التي في الملف في الـ Working Directory

لذا مع زيادة --staged يقوم Git بإحضار نسخة الملف من الـ HEAD المتواجد في الـ Local Repository
ثم يستبدله بالملف الذي في الـ Staging
كهذا سيصبح الملف الذي في الـ Staging مطابق لنسخة الملف الذي في الـ HEAD المتواجد في الـ Local Repository
وهكذا تراجعنا عن التعديل واخرجناه من مرحلة الـ Staging

لنفقم برؤية هذا بشكل عملي

> git status
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:   article_1.txt

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

لنفترض أننا وصلنا إلى هذه النقطة ثم قمنا بعمل git add بهذا الشكل

> git add article_1.txt

الآن سنقوم بعمل git status لنرى ما الذي حدث

> git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   article_1.txt

لاحظ أن الملف تم نقله إلى مرحلة الـ Staging
ونستطيع أن نقوم بعمل commit جديد في الـ Local Repository يضم التعديلات التي قمنا بها
عن طريق git commit

لكن نحن نريد ان نتعلم كيف نتراجع عن هذا التعديل لذا Git يساعدنا ويخبرنا كيف نفعل هذا
يقول لنا إن أردنا إخراج الملف فقط من مرحلة الـ Staging دون ان نتراجع عن التعديلات التي في الملف نستعمل git restore --staged article_1.txt

> git restore --staged article_1.txt

هكذا سيقوم Git بالذهاب إلى الـ HEAD المتواجد في الـ Local Repository واحضار نسخة الملف article_1.txt ويستبدلها بالملف الذي في الـ Staging
بالتالي نسخة الملف التي في الـ Staging ستكون مطابقة لنسخة الملف التي في الـ HEAD
بالتالي كأننا أخرجناه من حالة الـ Staging

لكن التعديلات التي في الملف مازالت موجودة
بمعنى أن نسخة الملف في الـ Working Directory مختلفة عن نسختها التي في الـ HEAD

وتذكر أن الـ HEAD يشير إلى آخر commit قمنا بعمله والذي يضم آخر التعديلات التي قمنا بتسجيلها داخل الـ Local Repository

يمكننا عمل git status ونتأكد

> git status
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:   article_1.txt

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

أنظر رجعنا لحالتنا الأولى قبل قيامنا بعمل git add article_1.txt
بمعنى أن التعديلات التي في الملف مازالت موجودة في الـ Working Directory لكن نحن فقط أخرجنا الملف من مرحلة الـ Staging

لذا نستطيع أن نقول أن git restore --staged هو الأمر الذي يعكس ما يقوم به الأمر git add

ملحوظة: تذكر git restore يقوم باسترجاع الملف من الـ Staging إلى Working Directory
أما git restore --staged يقوم باسترجاع الملف من الـ HEAD المتواجد في Local Repository إلى Staging

قبل أن نكمل لنقم بعمل git add و commit للملف article_1.txt

> git add article_1.txt

> git commit -m "edit article 1"
[main 6dc050b] edit article 1
 1 file changed, 1 insertion(+)

git rm file-name

نستخدم git rm عندما نريد حذف ملف من المشروع كليًا أي من الـ Working Directory ومن الـ Staging

وما يفعله أنه يحذف الملف من الـ Working Directory ثم يقوم بعمل git add تلقائيًا للملف المحذوف دون أن تشعر
والـ git add غرضها هنا وضع الملف المحذوف في مرحلة الـ Staging لتأكيد على حذفه في الـ commit جديد
بالتالي سيتم إنشاء نسخة جديدة من المشروع يكون الملف محذوفًا فيه

ملحوظة: يمكننا القول أن git rm هو في الحقيقة مزيج بين rm ثم git add

وبما أنها تحذف الملف من الـ Staging هكذا تم تحويل الملف إلى حالة Untracked بالتالي Git لن يتعرف عليه
لانه لم يعد Tracked File بالنسبة له
لكن في هذه الحالة الأمر لن يكون مهمًا لأن الملف لم يعد موجودًا في الـ Working Directory من الأساس

لنأخذ مثال عملي على ما قلناه
لنقم بإنشاء ملف جديد ثم نقوم بعمل git add و commit له
ثم نحاول حذفه من المشروع

> touch article_xyz.txt

> git add article_xyz.txt

> git commit -m "add xyz article"
[main c2d77c1] add xyz article
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 article_xyz.txt

> ls
article_1.txt  article_xyz.txt

الآن أصبح لدينا مقالة جديدة تدعى article_xyz.txt
لكن للأسف الشديد هذه المقالة تم إنشاءها عن طريق الخطأ ونريد أن نحذفها
لذا سنستعمل الأمر الجميل git rm

> git rm article_xyz.txt
rm 'article_xyz.txt'

الآن هنا حصل أمرين:

  • تم حذف الملف من الـ Working Directory
  • تم وضع الملف المحذوف في مرحلة الـ Staging للتجهيزه لعمل commit جديد

لنقوم بعمل git status للتحقق من ما قلناه

> git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    article_xyz.txt

لاحظ أنه يقول لك Changes to be committed أي أن هذه التعديلات التي في الـ Staging جاهزة لعمل commit
وأهم شيء ستلاحظ أن الملف article_xyz.txt يتم الإشارة إليه بأنه محذوف بمعنى انه سيتم حذفه في النسخة التي سينشئها الـ commit

لاحظ أنه أيضًا يقول لك بكيفية التراجع عن الحذف عن طريق git restore --staged article_xyz.txt
وهذا الأمر كما أوضحنا سيتم إرجاع نسخة الملف من الـ HEAD إلى الـ Staging
هكذا سنستعيد الملف في الـ Staging وسيصبح Tracked كما كان
لكن الملف محذوف أيضًا من الـ Working Directory لذا لكي تسترجعه بشكل نهائي ستحتاج لتنفيذ git restore article_xyz.txt
وهكذا سيتبدل الملف المحذوف من الـ Staging ألى الـ Working Directory
وهكذا سنستعيد الملف ويعود المشروع إلى حالته الاصلية
يمكنك أختبار طريقة إرجاع الملف المحذوف بنفسك

نحن لا نريد أن نسترجع الملف المحذوف لذا سنقوم بعمل الـ commit ليتم إنشاء نسخة من المشروع يكون الملف محذوفًا فيه

> git commit -m "delete xyz article"
[main 937637d] delete xyz article
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 article_xyz.txt

git rm --cached file-name

هذا هو نفس الأمر السابق لكن مع زيادة --cached
وهو في الحقيقة يشبه الأمر السابق لكنه لا يقوم بحذف الملف من الـ Working Directory بل يكتفي بأن يحذفه فقط من الـ Staging

وطالما أن الملف حذف من الـ Staging فقط فسيتم تحويل الملف إلى Untracked بالتالي Git لن يتعرف عليه لانه لم يعد Tracked File بالنسبة للـ Git

وتذكر أن الملف لم يحذف من الـ Working Directory بل حذف فقط من الـ Staging

سنعطي نفس المثال السابق بأننا سننشيء ملف ما ثم نحاول حذف

> touch article_xyz_again.txt

> git add article_xyz_again.txt

> git commit -m "add xyz article again"
[main cbbc411] add xyz article again
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 article_xyz_again.txt

الآن أصبح لدينا مقالة جديدة تدعى article_xyz_again.txt
ونريد أن نحذفها عن طريق الأمر git rm --cached

> git rm --cached article_xyz_again.txt
rm 'article_xyz_again.txt'

الآن ما حصل هنا هو مثل ما حصل الأمر السابق لكن مع اختلاف:

أن الملف حذف فقط من الـ Staging وليس من الـ Working Directory
وبالتطبع تم وضع الملف المحذوف في مرحلة الـ Staging للتجهيزه لعمل commit جديد

لنقوم بعمل git status للتحقق من ما قلناه مجددًا

> git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    article_xyz_again.txt

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

حسنًا أريدك أن تركز جيدًا في ما سأشرحه الآن
الأمر git status يخبرنا بمعلومتين مهمتين

الأولى أن الملف الذي حذفناه تم وضعه في مرحلة الـ Staging مع الإشارة إليه بأنه محذوف بمعنى انه سيتم حذفه في النسخة التي سينشئها الـ commit
الثانية أن نفس الملف موجود بالفعل في الـ Working Directory لكنه Untracked أي أن Git ينظر اليه كملف جديد لا يعرف عنه شيء
وهذا بسبب أن الأمر git rm --cached لا يحذف الملف من الـ Working Directory بل يحذفه فقط الـ Staging
وطالما أن الملف حذف من الـ Staging فبالتبعية سيتم تحويل حالة الملف من Tracking إلى Untracking

الآن لدينا شيء مميز هنا وأريدك أن تركز معي، إذا أردنا التراجع عن الحذف ما الذي سنفعله ؟
ستقول لي هذا سهل، فقط سنستخدم git restore --staged article_xyz_again.txt لنخرجه من حالة الـ Staging كما تعلمنا

صحيح، لكن ماذا سيحدث عندما نقوم بعمل git add article_xyz_again.txt ؟
سيتم وضع الملف article_xyz_again.txt في مرحلة الـ Staging وجعله Tracked
حسنًا وثم ؟ فكر وركز هنا جيدًا، ستتفاجيء ان الملف لم يعد مطالب حذفه
والمشروع عاد كمان كان إلي حالته الأصلية

بمعنى أن تنفيذ الأمر git add article_xyz_again.txt كان مساويًا تماما للأمر it restore --staged article_xyz_again.txt في هذه الحالة بالتحديد

هل تستطيع التفكير بالسبب ؟

السبب بسيط وهو أن الأمر git rm --cached، حذف الملف من الـ Staging فقط لا غير وأبقى الملف كما هو في الـ Working Directory
وهذا الملف الآن الموجود في الـ Working Directory مازال مساويًا للنسخة الموجودة في الـ HEAD داخل الـ Local Repository

كل ما في الأمر أنه ليس في الـ Staging!

لذلك عندما نستعمل git add سيتم إضافة الملف من الـ Working Directory إلى الـ Staging
وعندما نستعمل git restore --staged يتم نقل الملف من الـ HEAD إلى الـ Staging

إذًا في كلتا الحالتين ستكون نسخة الملف في الـ Staging متساوية مع النسخة التي في الـ Working Directory ومتساوية مع النسخة الموجودة في الـ HEAD المتواجد داخل الـ Local Repository

هكذا طالما أن كل النسخ متساوية، فكل شيء عاد كما كان قبل حذف الملف
والملف سيرجع Tracked كمان كان لأنه في الـ Staging
لذا النتيجة ستكون ذاتها بأن اصبحت كل النسخ متساوية

أرجوا أن تكون الفكرة وصلت الأمر يحتاج فقط لفهم طبيعة عمل كلا الأمرين git add وgit restore --staged

لنعود للأمر git status

> git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    article_xyz_again.txt

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

ونقول أننا نريد عمل commit لإنشاء نسخة من المشروع يكون الملف محذوفً فيه

> git add article_xyz_again.txt

> git commit -m "delete xyz article again"
[main be7a504] delete xyz article again
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 article_xyz_again.txt

الآن تم إنشاء نسخة جديدة لا يتواجد فيها الملف article_xyz_again.txt
لكن تذكر أن ملف لازال موجودًا في الـ Working Directory وحالته Untracked

لنتأكد من هذا عن طريق git status

> git status
On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        article_xyz_again.txt

nothing added to commit but untracked files present (use "git add" to track)

يمكنك أن تمسحه يدويًا الآن إن أردت أو أن تحتفظ به أو تضيف مجددًا، فلا يهم افعل ما تريده

أنا سأقوم بحذفه يدويًا لأنني لن احتاجه مجددًا

> rm article_xyz_again.txt

> ls
article_1.txt

git log

نستخدم git log عندما نرغب في مشاهدة تاريخ المشروع بالكامل وكل التعديلات التي تمت عليه من بداية المشروع حتى اللحظة الحالية
وكذلك لمعرفة من قام بإجراء التعديل ومتى قام بها

لذا عندما تريد رؤية جميع التغييرات والـ commit التي قمت بها في المشروع، فقط بضغطة زر تنفذ هذا الأمر البسيط git log

> git log
commit be7a50440aa044d331741b5af4758e23a190760d (HEAD -> main)
Author: AhmedEl-Tabarani <eltabaraniahmed@gmail.com>
Date:   Fri Apr 12 03:17:02 2024 +0200

    delete xyz article again

commit cbbc4119e47737ea5c96cd441b7bc69f51b16f1b
Author: AhmedEl-Tabarani <eltabaraniahmed@gmail.com>
Date:   Fri Apr 12 01:51:45 2024 +0200

    add xyz article again

commit 937637d020fbc80114f291c841d2f17f88f6178a
Author: AhmedEl-Tabarani <eltabaraniahmed@gmail.com>
Date:   Fri Apr 12 01:02:54 2024 +0200

    delete xyz article

commit c2d77c1cd3b94208816aefa916c8feb7f933f8ec
Author: AhmedEl-Tabarani <eltabaraniahmed@gmail.com>
Date:   Thu Apr 11 23:55:25 2024 +0200

    add xyz article

commit 6dc050b8d781d0247277fda29e8c330cd8b7f689
Author: AhmedEl-Tabarani <eltabaraniahmed@gmail.com>
Date:   Thu Apr 11 05:50:45 2024 +0200

    edit article 1

commit 4032898bcaf1dd2b5fbbaac2f15840e93097955f
Author: AhmedEl-Tabarani <eltabaraniahmed@gmail.com>
Date:   Thu Apr 11 03:25:33 2024 +0200

    add new article to the blog

وسيتم عرض لك جميع الـ commit التي كانت تخزن في الـ Local Repository
بالإضافة إلى عدة أمور منها الـ hash الخاص بالـ commit واسم الشخص الذي قام بالتعديل والوقت الذي تم فيه التعديل والرسالة التي كتبها مع الـ commit
فكما ترى لدينا العديد من الـ commit التي أنشأناها أثناء الشرح

لاختصار كمية المعلومات يمكننا ان ننفذ الأمر هكذا git log --oneline

> git log --oneline
be7a504 (HEAD -> main) delete xyz article again
cbbc411 add xyz article again
937637d delete xyz article
c2d77c1 add xyz article
6dc050b edit article 1
4032898 add new article to the blog

وكما ترى فأنه مفيد جدًا لرؤية آخر الـ commit التي اجريناها في المشروع
قد تجدني استخدم بعض الخيارات الاضافية معه كهذا git log --all --decorate --oneline --graph

خاتمة

كما تلاحظ، الآن أصبح لديك معرفة جيدة عن الأوامر الأساسية للـ Git وكيفية استخدامها
يجب أن تكون قادرًا الآن على إدارة مشروعاتك باستخدام Git وتنظيمها والقيام بالتعديلات والتحديثات بكل سهولة

بالطبع أنا لم اشرح جميع وظائف كل أمر، أنا فقط شرحت لك الفكرة والاستخدام العام لكل أمر
لكن اذا تعمقت ستجد ان كل أمر يحتوي على تفاصيل اعمق ودهاليز كثيرة
وأظن أنني اديت وظيفيتي في توصيل الهدف والاستخدام العام وهذا يكفي كبداية لتبدأ انت بجمع واستكشاف هذه الدهاليز والتفاصيل اثناء تقدمك وتعاملك

في المقالة التالية سنتكلم عن أوامر أكثر مثل git revert و git reset و git checkout و git stash
وسنفهم ما هو الـ HEAD وكيف نتحكم به

ويمكنكم قراءتها من هنا تكملة أوامر الـ Git والتحكم بالـ HEAD

ثم في مقالة أخرى سنتكلم عن الـ Branch في الـ Git
وأنها تعد من أهم المزايا التي يقدمها الـ Git
حيث أنها تساعدنا عن إنشاء عدة نسخ من المشروع، وكل نسخة تستطيع أن تطور فيها وتعدل وتفعل ما تريده دون أن تأثر على نسخة المشروع الأساسية
أو تقسم العمل ضمن الفريق حيث يمكن لكل عضو العمل على نسخته من الكود في فرع مختلف بشكل مستقل عن باقي الفريق

ويمكنكم قراءتها من هنا Git Branches آلة السفر عبر الأبعاد

ثم في المقالة التالية سنتكلم الـ Remote Repository وسنشرح مفاهيم وأوامر جديدة تتعلق بهذا العالم الآخر
ويمكنكم قراءتها من هنا التعامل مع Remote Repository وموقع GitHub