article cover image
مقدمة الى Git، الأداة التي يجب على كل مبرمج اتقانها
تطوير الويب والبرمجيات 28 دقيقة 1 تعليق 3379 مشاهدة
صورة المستخدم دريد عبدالله
مهندس برمجيات
تم النشر 2021-10-17 22:03:33 - آخر تحديث 2021-10-17 22:17:20

المشكلة التي نريد حلها

- كم مرة قمت بتطوير مشروع برمجي، امضيت الكثير من الوقت لجعله يعمل بشكل جيد، ثم اردت اجراء تعديلات او تجريب شيء مختلف، فقمت بتخريب المشروع ولم تعد قادرا على استعادته الى الوضع الذي كان يعمل به؟

- كم مرة احتجت لنسخ ولصق المشروع بكامله للمحافظة على نسخ مختلفة من المشروع كل واحدة منها تحوي اصدارا مختلفا قليلا او تعديلا ما؟

- كم مرة عانيت في مشاركة النص البرمجي الخاص بك مع زملائك، وقمت بضغطه وارساله عبر الدردشة؟ 

- كم مرة واجهت صعوبة في دمج التعديلات التي قام بها زميلك او زميلتك على نفس المشروع الذي قمت باجراء تعديلات عليه ايضا؟

أنظمة التحكم بالإصدار (Version control systems or vcs)

التحكم بالإصدار (version control) أو التحكم بالمصدر (source control) يشير الى عملية ادارة الرمز المصدري (source code) وتتبع وتسجيل التغيرات التي تطرأ عليه بشكل منظم.

أما أنظمة التحكم بالإصدار فهي الادوات التي تساعد المستخدم (عادة المبرمج) على القيام بهذه العملية، و Git (يلفظ هكذا)

قد يكون الأداة الأشهر في هذا المجال.

مع تطور منهجيات وطرق تطوير البرمجيات، وازدياد عدد الناس الذين يعملون في المجال، بات التحكم بالإصدار احد اهم الاسس التي تعتمد عليها صناعة ومشاركة البرمجيات اليوم، كما وتطورت انظمة التحكم بالاصدار وباتت اكثر تكاملا مع عملية تطوير البرمجيات برمتها. إني لا أبالغ ان قلت انها باتت صلب عملية تطوير وتوزيع ونشر (deploy) البرمجيات برمتها. 

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

فهم عقلية عمل Git

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

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

قبل الخوض في التفاصيل، دعنا نتفق على بعض المصطلحات الاساسية الضرورية لفهم الية عمل النظام

المَخْزَن (Repository)

يمكنك التفكير فيه على أنه المستودع الذي يحتوي النص البرمجي الخاص بمشروعك، مع جميع التعديلات السابقة التي قمت بها انت والاشخاص الاخرين على نفس المشروع. 

دعنا نتفق ان الخطوة الاولى للاستفادة من نظام التحكم بالاصدار هي انشاء مخزن Repository ليقوم بتتبع التغييرات التي تطرأ على مشروعك.

النقطة الزمنية (Commit)

عذرا، إلا انتي لم اجد ترجمة أفضل. الترجمة الحرفية لكلمة Commit تعني التورط او الالتزام. دعنا نفكر بها كنقطة زمنية في حياة النص البرمجي.

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

بالنسبة لنظام ادارة الاصدار، المشروع البرمجي ماهو الا عبارة عن سلسلة (او مجموعة) من النقاط الزمنية (commits) المترابطة مع بعضها بطريقة معينة، كما سنرى.

الفرع (Branch)

نظريا، معرفتك بالنقاط الزمنية جميعاً تكفي لتكون قادرا على التنقل بين اصدارات المشروع المختلفة، لكن مع ازدياد تعقيد المشروع، وازدياد المشاركين فيه، يصبح من الصعب جدا تذكر كل نقطة زمنية بعينها، ودمج التعديلات مع بعضها البعض.

من هنا، تنشا الحاجة الى مفهوم الفرع. 

الفرع هو حرفيا مؤشر يشير الى نقطة زمنية معينة، ويمكنك التفكير في كل فرع على أنه نسخة مختلفة من المشروع تقوم باستخدامها لتطوير ميزة معينة او تجريب شيء ما، عادة بشكل مؤقت. حالما تنتهي من تطوير هذه الميزة، يمكنك دمج التعديلات ضمن النسخة الرئيسية (او الفرع الرئيسي). 

الدمج (Merging)

يتكون المشروع عادة من فرع رئيسي (عادة ما يسمى master او main) حيث تنتهي جميع التعديلات النهائية هنا، ومن فروع اخرى مؤقتة يتم استخدامها لتطوير الميزات المختلفة.

عملية نقل التعديلات من فرع الى فرع تسمى بالدمج. فمثلا، اذا قمت بانشاء فرع جديد، وقمت باضافة ميزة تسجيل الدخول الى هذا الفرع، وتريد نقل هذه الميزة الى الفرع الرئيسي، فهنا انت بحاجة الى دمج فرع تسجيل الدخول مع الفرع الرئيسي.

المثال العملي سوف يوضح هذه العملية بالتفصيل.

المخزن البعيد (Remote repository)

تكلمنا منذ قليل عن المخزن على انه المكان الذي يخزن فيه كل ما يتعلق بالنص البرمجي وتعديلاته. وهذا الكلام صحيح، الا ان هذا المخزن عادة ما يكون على جهازك الشخصي.

هذا يعني ان الكود ليس امن تماما بعد، كما وانه لا يمكن مشاركته مع الاخرين. من هنا اتت فكرة المخزن البعيد، وهو مخزن مشابه لمخزنك المحلي، لكنه موجود على سيرفر اخر ويتم الاتصال معه عبر الانترنت، تقوم باستخدامه انت وزملاؤك الآخرون بغرض تخزين الكود بامان ومشاركته، 

أحد اشهر المواقع التي تقدم خدمة مخزن بعيد هو موقع GitHub، حيث يمكنك انشاء المخازن المختلفة، مشاركتها مع الاخرين، رفع الكود الخاص بك، استعراض اكواد الاخرين والنصوص البرمجية للكثير من المشاريع مفتوحة المصدر.

يمكنك باستخدام بعض الاوامر والتعليمات البسيطة القيام بعدد من العمليات المختلفة على المخزن البعيد، وهنا سأذكر اهم هذه العمليات فقط:

الجلب (fetch)

لجلب جميع البيانات الموجودة في المخزن البعيد وجعلها موجودة في المخزن المحلي. هذه البيانات قد تكون قد رُفعت من قبل زملائك في المشروع مثلا. هذا لا يؤثر ابدا على الكود الخاص بك، بل يجعل المخزن المحلي على دراية بجميع التعديلات الموجودة في المخزن البعيد، بحيث يمكنك معاينتها، مقارنتها مع ما لديك، وغير ذلك.

السحب (pull)

لجلب النقاط الزمنية (commits) التي اضيفت الى الفرع الذي تعمل عليه حاليا ودمجها مع النقاط الزمنية المحلية.

الرفع (push)

لإرسال جميع النقاط الزمنية الجديدة الموجودة في الفرع الذي تعمل عليه الى المخزن البعيد.

تطبيق عملي

سنقوم في هذا المثال بنسخ (Clone) مخزن بعيد قمتُ أنا باعداده ومشاركته على GitHub مسبقا، يحتوي على موقع انترنت بسيط.

سنقوم بعدها باجراء بعض التعديلات عليه، ومن ثم سندمجها في الكود الرئيسي ونرفعها الى GitHub كي تصبح متاحة للاخرين.

قبل البداية

تثبيت Git

قم بتثبيت Git باستخدام هذا الرابط. يحتوي هذا الفيديو على شرح مفصل لطريقة تثبيت واعداد غيت في ويندوز. اما بالنسبة لمستخدمي lunix فالامور ابسط بكثير: sudo apt install git-all

تأكد بعد الانتهاء من تثبيت البرنامج بشكل صحيح. يمكنك فتح نافذة اوامر جديدة وكتابة

git --version

يجب ان تحصل على اصدار البرنامج المثبت لديك.

اعدادات موقع GitHub

سوف نستخدم GitHub لتخزين وادارة المخزن البعيد. GitHub هو موقع مجاني يتيح استضافة مخازن Git ومشاركتها، مع العديد من الميزات الاخرى بشكل مجاني، كما ويحتوي على العديد من الميزات المدفوعة الموجهة للشركات. يعتبر GitHub اكبر مخزن انترنت للمشاريع مفتوحة المصدر حيث يمكنك ايجاد النص البرمجي لمعظم هذه المشاريع فيه.

  • قم بإنشاء حساب على موقع GitHub. لم أجرب ذلك منذ زمن طويل، اذا واجهتك اي مشاكل، اطرحها في التعليقات.
  • قم بتنزيل البرمجية الخاصة بالموقع (gh) لنظام تشغيلك بستخدام هذا الرابط. يمكنكم ايجاد تنزيلات مباشرة من هنا (قم باختيار الملف المناسب لنظام تشغيلك، عادة deb او rpm لابونتو، و msi لويندوز).
  • تاكد من تنزيل gh بشكل صحيح: افتح نافذة اوامر جديدة واكتب gh --version. يجب ان تحصل على اصدار التطبيق المنزل.

مصادقة git لاستخدام github كمخزن بعيد

سنحتاج للقيام بهذه الخطوة مرة واحدة، وهي ضرورية كي يتمكن Git من استعمال GitHub كمخزن بعيد باسمك أنت. 

لقد قمت مسبقا بتنزيل برمجية gh، الان للمصادقة:

افتح نافذة الاوامر واكتب gh auth login

 ستحصل على الخرج السابق، اضغط Enter لاختيار المصادقة الى GitHub.

سيتم سؤالك مجددا: ماهو البروتوكول المفضل لديك، ابق الخيار HTTPS كما هو واضغط Enter.

سيتم سؤال مجددا: هل تريد تسجيل الدخول باستخدام المتصفح، او باستخدام token. أبقي الخيار الافتراضي (المتصفح) واضغط Enter.

سيتم طباعة رمز مكون من ست خانات في نافذة الاوامر. قم بنسخ هذا الرمز ثم اضغط Enter

سيتم الان توجيهك الى موقع GitHub للمصادقة، قم باكمال باقي الخطوات وادخال الرمز عندما يتم سؤالك عنه.

بعد الانتهاء عد الى نافذة الاوامر لتجد الرسالة Authentication complete. Press Enter to continue...

اضغط على Enter، والان تمت المصادقة بنجاح! لن تحتاج للقيام بهذه العملية مجددا حتى اشعار اخر.

دعنا نبدأ

ما سنقوم بفعله الآن هو استخدام Git للقيام بجلب مشروع موجود في مخزن بعيد، ثم تشغيل هذا المشروع على جهازنا الشخصي. بعدها سوف نقوم باجراء بعض التعديلات ورفعها الى المخزن البعيد.

لقد قمت بإنشاء مشروع بسيط ورفعته الى GitHub، يمكنك استعراضه من هنا

الخطوات التي اتبعتها من اجل انشاء ورفع المشروع (للاطلاع فقط)

ليس عليك تنفيذها الآن، لكن من الجيد فهمها لتكون قادرا على انشاء مشروع مماثل ورفعه.

- ذهبت الى GitHub واخترت (انشاء مخزن جديد)، قمت بادخال اسمه وبعض الاعدادات وانشأت المخزن الجديد.

- ذهبت الى صفحة المخزن الجديد والذي يحتوي على ملف Readme فقط (اي مخزن فارغ) ونسخت رابطه من زر Code

- ذهبت الى terminal، واستنسخت المخزن البعيد (الذي لا يزال فارغ) محليا باستخدام الامر التالي

git clone https://github.com/doried-a-a/git-article.git

قام الامر السابق بنسخ المخزن البعيد مع ملفاته الى مجلد git-article والذي يحتوي افتراضيا على ملف Readme فارغ ومجلد مخفي .git يحتوي على جميع المعلومات التي يحتاجها git كي يعمل، بما فيها عنوان المخزن البعيد.

- الآن، قمت بأجراء التعديلات التي اريدها على هذا المخزن الفارغ (في حالتنا هذه، اضفت ملف index.html و styles.css)

- قمت بالطلب من git ان يتتبع هذه الملفات ويخزنها في نقطة زمنية (commit) من خلال الامر التالي:

git commit -am 'Add a webpage and styles file to the project'

هذا الامر يخبر Git بان يقوم بانشاء نقطة زمنية تحتوي جميع التعديلات المحلية (الخيار -a) وبأن يضيف الوصف المذكور بين علامتي اقتباس (الخيار -m). النقطة الزمنية (commit) تضاف الى الفرع (branch) الحالي، والذي يكون بشكل افتراضي هو main.

- قمت باضافة محتوى الى ملف التعليمات Readme وقمت بالطلب من Git ان يثبت هذه التعديلات من خلال نفس الامر السابق git commit لكن مع وصف مختلف.

- قمت بالطلب من git ان يرسل هذه التعديلات (النقاط الزمنية الجديدة في الفرع) الى المخزن البعيد من خلال الامر

git push

وبهذه الطريقة أصبحت جميع تعديلاتي موجودة في المخزن البعيد.

استنساخ المخزن البعيد محليا ومعاينته (قم بتنفيذه)

بشكل افتراضي، يمكنك استنساخ اي مخزن موجود على GitHub لكن لا يمكنك الرفع اليه (الا اذا قمتُ باضافتك الى قائمة الاعضاء المسموح لهم بالرفع). لتجاوز هذه العقبة، دعنا نقوم بنسخ المخزن البعيد المملوك من قبلي الى مخزن تملكه انت.

هذا سيؤدي الى خلق نسخة من هذا المخزن في حسابك الشخصي، حيث يمكنك رفع التعديلات وغير ذلك.

- اذهب الى صفحة المخزن الرئيسية

- ابحث عن زر "fork" وانقره، سيقوم هذا بنسخ المخزن الى مساحتك الشخصية، وبفتح المخزن المنسوخ الجديد

- دعنا الان نقوم باستنساخ المخزن من مساحتك الشخصية الى جهازك. ابحث عن زر Code او Clone وانقر عليه، اختر HTTPS وانسخ رابط المخزن. سوف يكون الرابط من الشكل https://github.com/$username/git-article حيث ان $username هو اسم المستخدم الخاص بك.

- اذهب الى نافذة الاوامر (terminal) في جهازك، انتقل الى المجلد الذي تريد وضع المشروع فيه، ثم نفذ امر النسخ (استبدل الرابط التالي بالرابط الذي قمت بنسخه)

git clone https://github.com/$username/git-article

سيقوم هذا بنسخ المشروع الى جهازك الشخصي ووضعه في مجلد يدعى git-article.  انتقل الى هذا المجلد

cd git-article

- باستخدام متصفح الملفات، انتقل الى المجلد السابق، واستعرضه. ستجده يحتوي ملفين index.html و styles.css وكلاهما تم جلبهما من المخزن البعيد (انا قمت برفعهما مسبقا). 

قم بتجريب صفحة الويب من خلال النقر المزدوج على الملف index.html كي يفتح في مستعرض الانترنت.

جميل الى حد الآن، أليس كذلك؟

حتى الان، قمنا بانشاء نسخة من المخزن الخاص بي، استنساخها محليا، معاينة الملفات الموجودة بها، وتجريبها.

الان، لديك مشروع git موجود محليا داخل المجلد git-article. دعنا نجرب ما الذي يمكننا القيام به الان.

اجراء تعديلات على المحتوى والتعامل مع بعض ميزات Git

حسنا، الان دعنا نجرب القيام باجراء بعض التعديلات على صفحة الانترنت، معاينتها، وتخزينها في فرع منفصل (branch) لتجريبها قبل اعتمادها بشكل نهائي.

قبل البداية، تاكد من ان نافذة الاوامر الخاصة بك موجودة بداخل المجلد git-article، يمكنك كتابة pwd لطباعة مسار المجلد الحالي، واستخدام cd  للتنقل بين المجلدات.

دعنا نتعلم امرين مفيدين في git:

كيف اعرف ما هو الفرع (branch) الذي اعمل عليه حاليا؟ باستخدام التعليمة 

git branch

قم بتنفيذ هذا الامر. سوف يخبرنا git ان اسم الفرع الحالي هو main وهو الفرع الوحيد. راجع تعريف الفرع اعلاه، وانتظر الاستخدامات العملية لمفهوم الفرع.

دعنا نلقي نظرة على جميع النقاط الزمنية (commits) الموجودة في الفرع main. اكتب الامر التالي:

git log main

ستحصل على خرج شبيه بالتالي:

وهذا سيظهر جميع النقاط الزمنية الموجودة في الفرع الحالي، مرتبة زمنيا بشكل معكوس. هذا يعني انه تم رفع ثلاث نقاط زمنية الى هذا الفرع، احداها تدعى Initial Commit والثانية تحتوي على "Add a webpage and styles.." والوصف (الذي اضفته يدويا) يخبرنا اننا قمنا هنا باضافة صفحة انترنت وملف ستايل. اما النقطة الاخيرة فتحتوي على رسالة تخبرنا بانه تم اضافة بعض التعليمات الى ملف التعليمات.

ملاحظة: من هنا، ترى انه من الضروري جدا اضافة رسائل معبرة الى النقاط الزمنية. تعتبر هذه من الخصال الجيد توافرها في المبرمجين.

دعنا نقم بمعاينة التغييرات التي حصلت في احدى هذه النقاط الزمنية. يمكنك دائما القيام بذلك باستخدام الامر التالي:

git show 0c503abdbe7f9ee6df7a7337f3e1fc4e35ea8a43

قم باستبدال الرمز الطويل الموجود في الامر السابق بالرمز الموافق للنقطة الزمنية التي تريد معاينتها. هذا الرمز يعتبر بمثابة معرف ID النقطة الزمنية.

لاحظ ان الامر السابق يظهر لك التغييرات التي حصلت في النقطة الزمنية، وليس جميع الملفات (هناك اوامر اخرى لاستعراض الملفات في نقطة زمنية),

دعنا نتأكد من وجود اي تعديلات محلية غير محفوظة في git. يمكنك دائما التحقق من هذا باستخدام الأمر

git status

وسيكون الخرج شبيها بالتالي:

مما يعني عدم وجود اي تعديلات ليتم تخزينها (او تتبعها).

دعنا نجري تعديلا على المشروع

الآن، افترض انه لديك هذا الاصدار من الموقع، وهو يعمل بشكل جيد، الا انك تريد تجربة القيام بتعديلة ما (مثلا، كتابة اسمك في الصفحة الرئيسية)، والاحتفاظ بها كاصدار اخر.

ببساطة، دعنا نقوم بانشاء فرع اخر حيث سنقوم باجراء هذه التعديلات و"حفظها" فيه (بالاحرى، تتبع هذه التعديلات باستخدام فرع اخر)، بحيث يبقى المشروع بصيغته الحالية في الفرع الرئيسي (main). دعنا نسمي هذا الفرع الجديد show_my_name. للقيام بذلك، اكتب الامر التالي:

git checkout -b show_my_name

الخرج المتوقع: Switched to a new branch 'show_my_name'

الامر السابق سيقوم بانشاء فرع جديد، وتغيير الفرع الحالي الى الفرع الجديد. هذا يعني ان كل النقاط الزمنية commits التي ستقوم بكتابتها الان سوف يتتم تتبعها من قبل الفرع الجديد.

الآن، قم بفتح الملف index.html باستخدام اي محرر نصي، وقم بتعديله لاضافة اسمك (مثلا، قم بتعديل هذا السطر واستبدل النص باسمك). بعد الانتهاء، احفظ الملف وقم باعادة فتحة باستخدام متصفح الانترنت للتاكد من عمل التعديلة بشكل صحيح.

الان، نريد ان نخبر git أن يقوم بتتبع هذه التعديلة. دعنا نجرب ان نسال git عن التعديلات التي لم يتم تخزينها (او تتبعها) بعد باستخدام الامر 

git status

هذه المرة ستحصل على خرج شبيه بالتالي، والذي يخبرنا بان الملف index.html يحتوي على تعديلات غير متتبعه

لاظهار هذه التعديلات، استخدم الامر التالي

git diff

سيكون الخرج شبيها بالتالي

لاحظ وجود سطر احمر واخر اخضر، هذا يعني انه تم حذف السطر الاحمر واضافة السطر الاخضر (بعبارة اخرى، استبدال السطر السابق بالسطر الجديد). هذا جيد، ففعلا هذه هي التعديلة التي قمنا بها.

دعنا نطلب من git الاحتفاظ بهذه التعديلة (من خلال انشاء نقطة زمنية) واعطائها وصفا مناسبا

git commit -am 'show my name in the homepage'

ولنقم الان باستعراض النقاط الزمنية الموجودة

git log

او 

git log show_my_name

(اذا لم تمرر وسيطا لـ git log فانها تقوم بالعمل على الفرع الحالي، والذي هو show_my_name في حالتنا)

سنحصل على خرج شبيه بالتالي:

بالنظر الى الخرج السابق، نرى وجود نقطة زمنية جديدة وهي التي قمنا باضفتها للتو لاظهار اسمنا في الصفحة الرئيسية.

لاحظ ان الفرع main لايزال يؤشر على النقطة الزمنية السابقة، في حين ان الفرع الجديد يؤشر على النقطة الزمنية الحالية. هذا صحيح، واي نقاط زمنية جديدة تتم اضافتها ستؤثر على الفرع الجديد فقط. 

يمكنك الان رفع التعديلات التي قمت باجرائها في الفرع الجديد الى المخزن البعيد باستخدام الامر

git push

وستحصل على رسالة خطا (مفادها بانه ليس هناك فرع بعيد مقابل للفرع الحالي)، لذلك ولمرة واحدة عند انشاء فرع جديد، ستحتاج لاستخدام الامر المقترح من خلال الخرج

git push --set-upstream origin show_my_name

الامر السابق، سيؤدي الى رفع الفرع الجديد الى المخزن البعيد، ورفع النقاط الزمنية الجديدة اليه. يمكننا استعراض هذه التفاصيل من واجهة GitHubـ حيث اثناء استعراض اي ملف او مجلد، يمكنك تغيير الفرع باستخدام القائمة المنسدلة. انظر الصورة المرفقة

حسنا، الان اصبحت تعديلاتك موجودة في المخزن البعيد، لكن في فرع جديد

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

قبل الدمج، دعنا نعود الى الفرع القديم (اي تغيير الفرع الحالي الى الفرع الاساسي)

git checkout main

ما الذي يعنيه هذا؟ هذا يعني ان تعديلاتك الاخيرة لم تعد موجودة! للتاكد من ذلك، قم بفتح الملف index.html باستخدام المتصفح (او حدث الصفحة).. ياللعجب، اين اختفى اسمك!؟

هذا طبيعي، فقد قمنا باعادة الملفات الى حالتها السابقة الموجودة في الفرع main، وبالنظر الى الفرع main باستخدام الامر git log ترى انه لا وجود للنقطة الزمنية التي قمنا فيها بتغيير الصفحة الرئيسية لعرض الاسم.

لكن لا تقلق، التعديلات لا تزال موجودة واذا رغبت في تغيير الفرع مجددا الى الفرع الذي يحتوي التعديلات، ما عليك الا كتابة

git checkout show_my_name

لكن لن نحتاج ذلك الان.

الان، نريد القيام باعتماد التعديلات الموجودة في الفرع الجديد (show_my_name) ونقلها الى الفرع الرئيسي (main). كيف نقوم بذلك؟

القيام بهذه العملية يشبه نسخ للنقاط الزمنية (commits) من فرع الى اخر، وللقيام بذلك هناك العديد من الطرق المختلفة، التي تختلف فعاليتها من حالة الى اخرى. 

لابقاء الامور بسيطة حاليا، دعنا نستخدم طريقة الدمج. ما يمكنك فعله هو دمج الفرع الجديد مع الفرع القديم، وللقيام بذلك، فانت بحاجة الى تنفيذ التعليمات التالية

git checkout main
git merge show_my_name

جرب تحديث الصفحة (او فتح الملف index.html)، واو لقد ظهر اسمك مجددا.

لفهم ما الذي حصل، اكتب من جديد git log وانظر الى الخرج

كما تلاحظ بامعان النظر الى النقطة الزمنية الاولى (show_my_name)، نرى امامها ثلاث مراجع:

HEAD -> main ما يعني ان الفرع الحالي (HEAD) والذي يدعى main اصبح يؤشر على هذه النقطة الزمنية، وهذا لاننا قمنا بدمج التعديلات من الفرع الجديد الى الفرع الرئيسي.

بالاضافة الى ذلك، نرى ايضا ان الفرع show_my_name ونظيره البعيد origin/show_my_name. يؤشران على نفس النقطة الزمنية.

على اية حال، لا نرى عبارة origin/main بجانب هذه النقطة، انما نراها بجانب النقطة التالية، وهذا يعني ان الفرع البعيد main (الموجود على المخزن البعيد) لا يزال لا يحتوي على اخر نقطة زمنية، وهذا طبيعي لاننا لم نقم بمزامنة التعديلات الجديدة على الفرع main بعد. للقيام بذلك، نفذ الامر

git push

وجرب كتابة git log من جديد

الان بات origin/main يشير الى نفس النقطة الزمنية وهذا يعني انه تم رفع التعديلات الى الفرع البعيد.

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

فهم الية عمل git، وفهم الفروع بشكل اعمق

الفرع (branch) في git ما هو إلا مؤشر لنقطة زمنية (commit)، يساعدنا على تتبع نقطة زمنية، او توالي من النقاط الزمنية بطريقة ابسط.

انتبه انه كان بامكانك كتابة 

git checkout 9bf7c943d32691c29e03389d87259c53e8c64c33

لاعادة شجرة العمل (الملفات) الى الحالة التي كانت بها في النقطة الزمنية المذكورة، الا ان استخدام الفرع اسهل

(اذا نفذت التعليمة السابقة، ستحتاج الى الانتقال الى فرع ما لاحقا، مثلا الى الفرع الرئيسي git checkout main، والا فلن تكون قادرا على انشاء اي نقاط زمنية، لان المؤشر HEAD يجب ان يشير الى فرع تتم اضافة النقاط الزمنية اليه، ليس الى نقطة زمنية)

بالاضافة الى ذلك، وعلى الرغم من ان الفرع يشير الى نقطة زمنية معينة حاليا، فانه عندما تقوم بانشاء نقاط زمنية اضافية، فإنها تضاف الى نفس الفرع (يصبح الفرع يشير الى النقطة الزمنية الجديدة، وتشير النقطة الزمنية الجديدة الى القديمة، اي تصبح اشبه بسلسلة مترابطة من النقاط الزمنية).

انظر الى الشكل التالي

في الصورة السابقة، كل دائرة تمثل نقطة زمنية (commit)، وكل نقطة زمنية لديها نقطة تدعى الأب (parent) هي النقطة التي اتت منها. دعنا ننظر الى الخط السابق من اليسار الى اليمين.

الخط الأزرق يمثل جميع النقاط الزمنية الموجودة في الفرع الرئيسي (main).

بالنظر الى الفرع البنفسجي (Little featre) نرى ان أحدهم قام بإنشاء فرع بدءا من نقطة زمنية سابقة وقام باضافة نقطة زمنية الى ذلك الفرع (مثلا، يمكنك ان تقول قام بتغيير لون احد الازرار ثم قام بـ commit). كما نرى، هذه التعديلات ليست في الفرع الرئيسي بعد، لانه لم يتم دمجها بعد.

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

ثم قام شخص ما بانشاء فرع جديد بدءا من الفرع الرئيسي، واضاف اليه ثلاث نقاط زمنية، ثم قام احدهم باضافة نقطة الى الفرع الرئيسي.

الآن، لدينا ثلاث فروع قيد التطوير في نفس المشروع، وقد تحتوي هذه الفروع على نسخ مختلفة جدا من هذا المشروع. يجب على المطورين الذين يعملون في هذه الفروع ان يقومو بدمج هذه الفروع بالفرع الرئيسي (او نقل النقاط الزمنية الى الفرع الرئيسي) كي تصبح هذه التعديلات "معتمدة".

التعارضات (conflicts)

من البديهي التفكير في حالة قيام مطورين مختلفين باجراء تعديلات على نفس الملف في فروع مختلفة، ثم قيام هؤلاء المطورين بدمج هذه التعديلات في الفرع الرئيسي.

في هذه الحالة، سيظهر ما يسمى بالـ "تعارضات" او (conflicts) عندما يقوم الشخص الثاني بدمج تعديلاته. وهي ظاهرة شائعة عندما يتم العمل من قبل مجموعة اشخاص على نفس الملفات في الوقت ذاته. يمكن حل هذه التعارضات ببساطة (احيانا ما يتطلب هذا تدخل يدوي) قبل دمجها بالفرع الرئيسي.

بالنسبة لي شخصيا، عادة ما استخدم IDE لحل التعارضات، بحيث يمكنني عرض التغييرات جنبا الى جنب ومقارنتها.

ماذا لو اردت العودة الى نقطة زمنية سابقة من المشروع

يمكنك القيام بذلك بكل سهولة، فاذا اردت العودة الى نقطة زمنية سابقة بشكل مؤقت، يمكنك استخدام الامر git checkout $comimit (استبدل $commit برمز النقطة الزمنية).

اما اذا اردت تجاهل جميع التعديلات التي تمت بعد تلك النقطة الزمنية، فيمكنك إعادة تعيين RESET الفرع الخاص بك الى تلك النقطة الزمنية. git reset HEAD $commit أو git reset --hard HEAD $commit.

كن حذرا جدا اثناء استخدام الامر الاخير لانه يؤدي الى فقدان اي نقاط زمنية وجدت بعض النقطة التي تريد اعادة التعيين اليها (ستبقى النقاط الزمنية موجودة، لكن لن يمكنك الوصول اليها الا اذا كان هناك فروع اخرى لا تزال تشير اليها، او اذا كنت لا تزال تذكر ارقامها :P)

استخدام Git في الحياة العملية

قد يسأل البعض، هل انا بجاجة الى معرفة اوامر git المختلفة؟ الا يمكنني استخدامه من خلال واجهة رسومية؟

أجل. معظم بيئات التحرير (IDEs) تملك دعما جيدا جدا لميزات git المختلفة (مثل IntelliJ Idea, phpStorm, eclipse, atom, VS code) وغيرها الكثير.

أي انك في معظم الاحيان لن تضطر لكتابة الاوامر، او لمقارنة التعديلات في الترمنال، انما في نافذه تعرض الاختلافات جنبا الى جنب وتجعل عمليات حل التعارضات اسهل بكثير.

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

في الختام

ما قدمته في هذه المقالة هو غيض من فيض. لا يزال لدى git بحر هائل من الخيارات والميزات الاخرى، التي تتطلب الممارسة لاتقانها والاستفادة منها.

الا انني اتمنى ان اكون قد اوصلت الفكرة الرئيسية من هذه المقالة، بشكل رئيسي عن حالات استخدام git، متى يمكنك الاستفادة منه، ماهي الاوامر الرئيسية للتعامل معه، كيف يمكنك انشاء ومشاركة الكود مع الاخرين، والتعاون في المشاريع البرمجية.

لا تتردد بطرح اي اسئلة او استفسارات في التعليقات، واخبرني اذا ما اخطأت في اي نقطة.

يمكنك مشاركة رابط المقال مع الاخرين، لكن فضلا النسخ غير مسموح.

التعليقات (1)