لماذا نحتاج Git؟ فهم نظام التحكم في الإصدارات الذي لا غنى عنه

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

أو قد أفكر بطريقة أذكى قليلاً وأقول له إنني سأرسل لك الكود عبر البريد الإلكتروني كلما أجريت تحديثًا جديدًا. أو قد أقترح إنشاء مجلد على Google Drive ونرفع عليه الكود المحدث، ثم يقوم هو بتنزيله.

المشكلة الحقيقية

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

الحل: نظام Git

لكي نتجنب كل هذه المشاكل، نستخدم أداة تسمى Git. إن Git هو الحل الأمثل للتعاون في المشاريع والعمل معًا. بل وأخذوا خطوة إضافية حيث يمكنك استخدامه لإجراء عمليات النشر (Deployment)، ومع كل تحديث جديد، يتم بناء نسخة جديدة ورفع الكود. إن Git هو الأداة السحرية في عالم البرمجة التي نريد أن نتحدث عنها في هذا المقال. لماذا نستخدم Git، ولماذا من المهم أن تتعلمه بشكل صحيح؟

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

ما هو Git؟

Git هو أداة نظام تحكم في الإصدارات (Version Control System)، وهي أداة لتنظيم ملفاتك على شكل إصدارات (Versions). كلما غيرت مجموعة من التغييرات، تقوم بإغلاقها في ما يسمى “commit” وتصنع منها إصدارًا. بعد الانتهاء، تقوم بعمل الـ “commit” التالية. الـ “commit” هي مجموعة من التغييرات التي تجريها على الملفات، وبذلك أنت تنشئ تاريخًا للتغييرات (History of Changes) أو سجل إصدارات (Version History). بهذا، لا أقع دائمًا في فخ أنني إذا وصلت إلى نقطة تعطل فيها كل شيء، لا أستطيع التراجع خطوة صغيرة للوراء. مع Git، يمكنك التراجع بسهولة.

لقد أتاحت فكرة وجود Git كـ “نظام تحكم في الإصدارات” الفرصة لشركات كثيرة جدًا للتعاون مع بعضها، كما أتاحت فكرة عمل الأشخاص عن بعد ومن أي مكان في العالم. في الحقيقة، كل ما أفعله هو أنه يكون هناك ما يسمى خادم نظام التحكم في الإصدارات (Version Control System Server) يوجد عليه الكود والتاريخ الكامل منذ بدأنا كتابة الكود في المشروع. وعندما يأتي شخص للعمل على جهازه، يأخذ نسخة منه، ونحن نسميها مستودع Git أو (Git Repo). يأخذ نسخة عنده على الجهاز ويبدأ بالعمل وإجراء التغييرات، ثم يقوم بعمل “commit”. وكما اتفقنا، الـ “commit” تحتوي على مجموعة من التغييرات التي أجراها، وقد تكون ميزة كاملة (feature) يقوم ببنائها ويضعها في “commit” واحدة. بعد أن ينتهي من عمله، يأخذ هذه الـ “commit” ويقوم بعمل push لها لتعود إلى الخادم مرة أخرى.

الفكرة هي أنه يمكن ببساطة أن يكون لدي مشروع يعمل عليه أكثر من 50 أو 100 أو حتى 1000 موظف دون أي مشكلة، لأن في النهاية، عمل كل هؤلاء الأشخاص يتم تركيبه فوق بعضه البعض باستخدام خوارزميات Git المعقدة لدمج كل هذه الـ “commits” معًا في تاريخ واحد. وهذا ما نريد أن نتعرف عليه ونفهم كيف تتم هذه العملية المعقدة.

أساسيات ومصطلحات Git

دعونا نبدأ ببعض الأساسيات التي ذكرناها بالفعل، ولكن أريد أن أركبها على شكل مصطلحات لجعل الموضوع رسميًا أكثر.

لكن في الواقع العملي، هذا ليس ما يحدث غالبًا. عادةً، عندما تنضم إلى مشروع مع شركة أو شخص ما، يكون لديهم بالفعل تاريخ مكون من الـ “commits”، وأنت تريد سحب نسخة منه. لذا، تقوم بعملية تسمى git clone، حيث تأخذ نسخة (clone) من المستودع. أنا لست مهتمًا الآن أين يوجد هذا الخادم؛ قد يكون على GitHub، أو GitLab، أو Bitbucket. كل هذه الشركات تقدم لك فكرة أن يكون لديك مستودع بعيد (Remote Repo) أو خادم (Origin Server) مرفوع عليه الكود، ويمكن لأي شخص أن يأخذ نسخة منه.

للحصول على صلاحية الوصول (access) إلى الخادم، هناك حلول كثيرة لجعل الموضوع آمنًا. إما باستخدام مفتاح (key) أو رمز وصول (access token) يمنحك صلاحية الدخول إلى المستودع وأخذ نسخة منه، خاصة إذا كان المشروع حساسًا ولا يمكن فتحه للعامة. ولكن هناك مشاريع مفتوحة المصدر (open source) تكون متاحة للجميع لسحب نسخة منها، وهذا ما تجده عادةً في مكتبات برمجية كثيرة مثل مكتبات Microsoft، أو JavaScript، أو Node.js، أو Python، وغيرها.

آلية العمل الأساسية

لنفترض أنك حصلت على صلاحية الوصول إلى مستودع خاص (private repo) وأنشأت المفتاح وسحبت نسخة محلية. ماذا تعني عملية clone؟

الـ clone تعني أنك أخذت نسخة متكاملة من التاريخ الكامل الذي كان موجودًا على الخادم البعيد. فلو كان الخادم البعيد يحتوي على 10 “commits”، فإن هذه الـ “commits” هي مجموعة من التغييرات التي حفظتها في قالب. هذا القالب (الـ “commit”) نعطيه رسالة تصف التغييرات التي قمنا بها. قد أكون أحل خطأً برمجيًا (bug) صغيرًا في ملف أو اثنين أو ثلاثة. عندما أنتهي من حل الخطأ، أقوم بعمل “commit” لعملي.

  1. الإضافة إلى منطقة التجهيز (Staging Area): أولاً، أضع الملفات في منطقة تسمى Stage باستخدام أمر git add.
  2. إنشاء الـ Commit: بعد ذلك، أقوم بإنشاء الـ “commit” مع رسالة تصف التعديلات التي قمت بها، مثل: “قمت بحل خطأ في كذا وكذا وكذا”.

أصبح لهذا الأمر اليوم معايير. بعض الشركات تشترط أن تكتب رسالة الـ “commit” بنمط معين، على سبيل المثال:

feat(TICKET-123): Add new login feature

هنا، feat هي اختصار لـ feature، ثم تفتح قوسين وتكتب رقم التذكرة (ticket) من نظام تتبع المهام مثل Jira، ثم نقطتين، ثم رسالتك. الهدف من هذا النمط هو توحيد شكل كل الـ “commits”.

فائدة الـ “commits” أنها تسير بشكل متسلسل وغير قابل للتغيير (immutable)، حيث تكون مترابطة. الـ “commit” الأولى تشير إلى التي تليها، وهكذا. هذا يشبه هيكل بيانات (data structure) مشهور في البرمجة يسمى القائمة المرتبطة (Linked List). هذه السلسلة من الـ “commits” هي التي تشكل سجل الإصدارات (Version History) أو سجل الـ “commits” (Commit Log).

الميزة هنا هي أنه طالما لديك تاريخ الـ “commits” هذا محليًا، يمكنك تجربة التراجع خطوة للوراء. افترض أن لديك 10 “commits”، واكتشفت أن الـ “commit” الأخيرة تحتوي على عيب خطير. يمكنك العودة إلى الـ “commit” رقم 9 باستخدام أمر مثل git revert. هذا الأمر سيعكس التغييرات التي تمت في الـ “commit” الأخيرة، مما يسمح لك بإصلاح المشكلة.

الدفع والسحب (Push & Pull)

عندما تقوم بعمل “commit”، فأنت لا ترفعها مباشرة إلى الخادم. هذا أمر يجب الانتباه إليه جيدًا. تذكر دائمًا أن لديك مستودعًا محليًا (local repo) ومستودعًا بعيدًا (remote repo). الـ “commit” الجديدة يتم حفظها في مستودعك المحلي.

لذلك، من الممارسات الجيدة في الشركات أن تبدأ يوم عملك بعمل git pull لسحب آخر التحديثات الموجودة على الخادم.

العمل بالفروع (Branches)

لنفترض أنني أريد إجراء تعديلات ومشاركتها مع زملائي، ولكن ليس من المعقول أن نعمل جميعًا في نفس المكان ونرفع الـ “commits” مباشرة. هنا نستخدم ما يسمى الفروع (Branches).

الفرع (branch) يبدأ بالتفرع من عند آخر “commit” وقفت عندها في الفرع الرئيسي (main). ثم تبدأ بالعمل وإنشاء “commits” جديدة على هذا الفرع الجديد، تمامًا مثل فروع الشجرة. التعديلات التي تقوم بها تكون على فرعك الخاص فقط، ولن تظهر على الفرع الرئيسي (main) حتى تقرر دمجها. هذا ما نسميه فرع الميزة (feature branch)، حيث أضع الميزة التي أعمل عليها في فرع منفصل.

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

طلبات السحب والدمج (Pull/Merge Requests)

بعد أن ننتهي من عملنا على فرع الميزة، نفتح ما يسمى طلب سحب (Pull Request) في GitHub أو طلب دمج (Merge Request) في GitLab. من خلال هذا الطلب، تطلب ضم العمل الذي قمت به على فرعك إلى الفرع الرئيسي (main).

هنا تأتي فائدة مراجعة الكود (Code Review)، حيث يمكن لزملائك رؤية الكود الذي كتبته وترك تعليقاتهم وملاحظاتهم قبل الموافقة على الدمج.

استراتيجيات الدمج (Merge Strategies)

عندما تكون جاهزًا للدمج، هناك عدة استراتيجيات:

  1. الدمج الصريح (Explicit Merge): هذه هي الطريقة الافتراضية. يتم أخذ كل الـ “commits” من فرعك وإضافتها إلى الفرع الرئيسي، بالإضافة إلى “commit” جديدة تسمى Merge Commit. هذا قد يسبب “ضوضاء” في تاريخ الفرع الرئيسي لأنه يضيف الكثير من الـ “commits” التفصيلية.

  2. الدمج بالضغط (Squash and Merge): تلجأ معظم الشركات إلى هذه الطريقة. يتم ضغط كل الـ “commits” الموجودة في فرعك (سواء كانت 5 أو 30) في “commit” واحدة فقط عند دمجها في الفرع الرئيسي. هذا يجعل تاريخ الفرع الرئيسي نظيفًا وواضحًا وسهل التتبع. إذا احتجت للتراجع، ستتراجع عن “commit” واحدة فقط.

  3. الدمج بالتقديم السريع (Fast-Forward Merge): في هذه الطريقة، يتم أخذ الـ “commits” من فرعك ووضعها مباشرة فوق آخر “commit” في الفرع الرئيسي، كما لو أن فرع الميزة لم يكن موجودًا أصلاً. هذه الطريقة قد تكون مشكلة لأنها تخفي حقيقة أن العمل تم على فرع منفصل، مما يفقدنا جزءًا مهمًا من التاريخ.

الخلاصة: أهمية Git

في النهاية، يتضح مدى أهمية Git وما يوفره من مسار عمل (Git Flow) منظم. من المهم جدًا أن تستوعب هذا المسار، وتفهم كيفية إنشاء فروع الميزات، والعمل عليها، ثم دمجها مرة أخرى في الفرع الرئيسي. إذا لم تستخدم Git وعملت بطريقة بدائية باستخدام الذاكرة المحمولة أو Google Drive، ستنسى بنفسك المشاكل التي حُلّت وما الذي حدث. لكن مع Git، يبقى كل شيء مسجلاً.

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

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

شارك المقال

أحدث المقالات

CONNECTED
ONLINE: ...
SECURE
00:00:00