الرئيسية > مقالات > نظام Git: الأساسيات وأفضل الممارسات وكيفية الالتزام بنظام GitFlow

نظام Git: الأساسيات وأفضل الممارسات وكيفية الالتزام بنظام GitFlow

نظام Git: الأساسيات وأفضل الممارسات

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

اساسيات نظام Git:

يعد نظام Git هو نظام التحكم بالإصدار (version control system) الأكثر استخداما. وتعتمد فكرته في الأساس على تتبع سلسة التغييرات التي تقوم بها على الملفات، فيصبح لديك سجل (log) بالإضافات والحذف والتعديلات التي قمت بها منذ بدء المشروع، فيمكنك العودة إلى إصدارات محددة إذا احتجت إلى ذلك.

يعتمد Git على ثلاثة بيئات للعمل:

  • Working Directory: المكان الذي تقوم فيه بإنشاء وحذف وتعديل ملفات المشروع.
  • Staging Area: المكان الذي نقوم فيه بإدراج الملفات التي نرغب لـ Git أن يحفظها.
  • Repository: المكان الذي يستخدم للتخزين النهائي للملفات. 

عادة ما يتم استخدام Git كالتالي:

  • تهيئة نظام Git ليبدأ تتبع التغييرات. 
  • بعد القيام ببعض التعديلات تقوم بإضافة الملفات من الـ working directory الى الـ staging area.
  • يمكن الإطلاع على الوضع الحالي للملفات في أي وقت لترى اي الملفات تمت اضافتها للـ staging area.
  • يمكنك الاطلاع علي جميع التغييرات التي قمت بها في الملف.
  • اخيرا تقوم بحفظ التغييرات التي قمت بها مع إضافة رسالة ليسهل عليك الرجوع الي هذا التغيير وبذلك ينتقل الملف الي الـ repository area.
  • يمكنك الحصول علي سجل بالتعديلات التي قمت بها في اي وقت.
git init
git add filename 
git status 
git diff // Check the differences
git commit -m "Initial commit" 
git log

انت الان تحتفظ بكل التعديلات التي قمت بها في الكود وتستطيع العودة إليها اذا ما احتجت الي ذلك ولكن أحيانا لا نكون متأكدين من الكود الذي كتبناه أو من الميزة feature الجديدة التي أضفناها ونود أن نجرب إضافتها بشكل مختلف، في هذه الحالة:

  • تقوم بعمل فرع branch جديد للكود الذي تنوي كتابته.
  • ثم بعد المراجعة تقوم بدمج merge الكود الجديد في الفرع الرئيسي.
  • ثم تقوم بحذف الفرع الجديد.
git branch branchName // create new branch
git checkout branchName // Go the new branch
git checkout main // go to the main branch
git merge branchName // merge the code to main 
git branch -d branchName // delete the branch

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

للتعاون مع فريق العمل من خلال Git، غالبًا سوف يقوم كل فرد بالعمل على النحو التالي:

  • عمل نسخة clone من ال repo على الجهاز الخاص بكل فرد للعمل عليها دون المساس بالنسخة الأصلية والتي يتم تسميتها في أغلب الأوقات origin. 
  • ثم يقوم بعمل fetch ودمج لأية تعديلات من الـ origin.
  • ثم يقوم بعمل branch جديد للقيام بالتعديلات التي يود القيام بها. 
  • وتحسبًا أن يكون تم تحديثات على النسخة المشتركة origin يقوم بعمل fetch وmerge مرة أخرى.
  • في النهاية يقوم بإضافة تعديلاته على النسخة المشتركة. 
git clone repoLocation cloneNameOfChoice
git fetch 
git merge origin/branchName
// Create a featureBranchName
// Repeat fetch and merge
git push branchName origin

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

لا يفوتك أيضا: 7 مهارات تمنيت كمبرمج لو تعلمتها منذ البداية

تعرّف على طريقة سير العمل الصارمة GitFlow

كما تحدثنا، فإن الهدف من ال GitFlow هو ضمان جودة واستقرار الكود. وهو يعتمد على تخصيص أدوار معينة للفروع branches المختلفة، ويحدد متى و كيف تتفاعل هذه الفروع مع بعضها البعض. يعتمد نظام سير GitFlow على وجود فرعين أساسيين للمساهمة عليهم: الفرع الرئيسي main ويُعرف أيضًا بفرع الإصدار release branch وفرع التطوير develop.

 طريقة سير العمل الصارمة GitFlow
  • يكون الفرع الرئيسي مسؤولًا فقط عن إصدار النسخ النهائية من التطبيق؛ ولا يجب عمل أي فروع منبثقة من هذا الفرع بخلاف فرع الـ develop إلا في حالة إكتشاف مشكلة عاجلة في التطبيق وتوجب علينا إصلاح هذه المشكلة فورًا.
  • في هذه الحالة، نقوم بإنشاء فرع جديد hotFixBranch من الـ main؛ نقوم بإصلاح المشكلة وندمج الكود مرة اخرى مع الـ main.
  • أما فرع التطوير فنستخدمه لدمج الـ features في كل مرة نقوم بإنشاء feature جديدة أو نقوم بإصلاح bug. وهذا الفرع يحتوي على التاريخ الكامل للمشروع. 
  • عند إضافة خاصية جديدة feature أو اكتشاف خطأ غير مؤثر يجب عمل فرع جديد للخاصية ثم نبدأ العمل من خلال سلسلة من المساهمات commits بعد ذلك نقوم بفتح pull request لدمج التغييرات الى فرع الـ develop.

بهذه الطريقة يكون الفرع الرئيسي جاهزا في أي وقت للإصدار ويكون بنسبة كبير خاليًا من العيوب الخطيرة وبذلك تزيد كفاءة الكود ويصبح التطبيق أكثر إستقرارا؛ وفي نفس الوقت يستطيع المطورون من العمل بشكل متزامن سواء في فروع الـ fetaures أو الـ bugFixes.

حسنًا، الآن يمكننا استخدام Git ويمكننا تطبيق GitFlow ولكن يمكننا دومًا التحسن في إستخدام Git، دعنا نحاول استعراض بعض أفضل الممارسات عند استخدام Git.

أفضل الممارسات عند استخدام Git

سنحاول في هذا الجزء تحديد بعض النقاط المفيدة عند التعامل مع Git ولكن أهم هذه النقاط هي كتابة الـ commit message بشكل واضح حيث تعد هذه الرسائل المصممة جيدًا أفضل طريقة لإيصال السياق المطلوب حول التغييرات التي تمت لزملائك في الفريق. لذلك دعنا في البداية نتحدث عن الطريقة الأفضل لكتابة رسائل الـ  commits:

  • اجعل الـ commits الخاصة بك واضحة وذات هدف واحد؛ فمثلا عندما تحاول تصحيح خطأ و اكتشفت خطأ آخر، اجعل لكل خطأ الـ commit الخاص به حتي لا تنتهي بتغييرات كتيرة ليس لها صلة ببعض.
  • اجعل الرسائل الخاصة بالـ commit معبرة عن التغييرات التي حدثت حتى يسهل الرجوع لها فيما بعد. 
  • افصل العنوان عن مضمون الرسالة بخط فارغ. ابدأ الرسالة بسطر واحد قصير (أقل من 50 حرفًا) يلخص التغيير الذي قمت به، وفي حال احتجت كتابة وصف للتغيير الذي حدث، اترك سطرًا فارغًا ثم اكتب الوصف الذي تريده. 
  • استخدم صيغة الأمر في كتابة الرسالة كأنك تلقى امرًا او تعطي تعليمات، بهذا نكون متسقين مع طريقة Git في كتابة الأوامر التي يستخدمها.
  • استخدم الوصف للإجابة عن ماذا ولماذا هذا التغيير وليس الكيفية (سوف يقوم الكود بالإجابة عن كيف)، ركز على توضيح أسباب إجراء التغيير في المقام الأول – الطريقة التي سارت بها الأشياء قبل التغيير (وما الخطأ في ذلك)، والطريقة التي تعمل بها الآن، ولماذا قررت حلها بالطريقة التي فعلت.
  • إذا كنت قد أنشأت commit بالفعل، ولكنك تقوم بعد ذلك بالمزيد من العمل الذي يجب تضمينه منطقيًا في نفس الالتزام، يمكنك ببساطة إضافة العمل الجديد إلى الـ commit السابق باستخدام       git commit –amend –no-edit

إليك بعض النقاط الأخرى التي ستساعدك على استخدام Git بالشكل الأمثل:

  • قم بحذف الـ Local Branches التي تم حذفها من Remote Repository. 
  • قم بإضافة ملف .gitignore في بداية مسار مشروعك. يستخدم Git هذا الملف لتحديد الملفات والمسارات التي لا نريد لـ Git تتبعها مثل تلك الملفات التي يتم إنشاؤها من بناء وتشغيل المشروع.
  • استخدم  git bisect  لمعرفة أول commit يحتوى على خطأ لكن يجب أن تخبر bisect علي commit ID يحتوي على الخطأ و commit ID  آخر لا يحتوى على خطأ و سيبدأ bisect  في البحث عنه.
  • استخدم git stash إذا كنت تريد حفظ التغييرات لاستخدامها لاحقا؛ مثلا إذا أردت العمل على خاصية جديدة و ترك تعديلاتك على الخاصية الحالية للرجوع لاستكمالها فيما بعد. 
  • استخدم العلامات tags لتكون المرجع لنقطة معينة في سجل git مثل استخدامها لتحديد الإصدارات من المشروع git tag 1.0.0 dc7a3cf.
  • استخدم الامر git log –oneline لعرض السجل في صورة مختصرة ويمكن الانتقال لأى نسخة باستخدام الرقم المختصر الموجود بدلا من استخدام الـ Commit ID  كما يمكنك استخدام اكتر من أمر لعرض السجل بشكل آخر؛ مثلا إذا أردت عرض الـ commits الخاصة بمبرمج معين git log –author = ali. 
  • (خاص بـ Github) اجعل الـ Pull Request الخاص بك يحتوى على كل المعلومات المطلوبة ليتم مراجعته بسهولة و دمجه مع الفرع الرئيسى و يفضل استخدام Pull Requests Templates لكي يتم انشاء شكل الوصف تلقائيا وعليك فقط إدخال التغييرات التي قمت بها. 
// git bisect
git bisect start
git bisect bad head 
git bisect good dc7a3cf
git bisect reset

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

  • يجب أن يحتوي الفرع الرئيسي main branch فقط على الكود الذي تمت مراجعته reviewed و دمجه عبر طلب سحب pull request.
  • يجب إضافة فرع منفصل لكل ميزة feature/ إصلاح fix / إعادة بناء refactor مما يجعل من الأسهل كثيرًا التراجع عن تغييرات معينة، وتحديد مصدر الأخطاء.
  • يجب أن يكون كل التزام commit صغيرًا قدر الإمكان، مع مراعاة كتابة رسالة التزام جيّدة تشرح سبب إجراء التغيير.
  • حافظ على تحديث نسختك المحلية local version من هذا الفرع branch بالتغييرات من الفرع الاونلاين remote branch.
  • يجب أن تتم عمليات النشر deployment / release من الفرع الرئيسي main branch ، وليس من فرع اختبار test branch.
  • يجب أن يتم الدمج merge فقط باستخدام طلبات السحب pull request.

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

الفرق بين git merge وgit rebase

يوجد طريقتين اساسيتين لدمج التغييرات من فرع لاي فرع اخر، وهما git merge و git rebase. يقوم كلا الأمرين بدمج التغييرات، ولكن عند استخدام git merge يتأثر فقط الفرع الذي يتم الدمج إليه الـ main، اما الفرع المصدر feature أو الـ bug فيبقي تاريخ الـ commits كما هو ولذلك يفضله البعض لانه يحتفظ بتاريخ التغييرات دون مساس، أما git rebase فانه يقوم بضغط كل التغييرات في الفرع المصدر إلى تغيير واحد ثم يقوم بدمجه في الفرع الآخر main، فهو يقوم بإعادة تاريخ الـ commits، ويفضله البعض لأنه يسهّل عملية المراجعة.   

الفرق بين git merge و git rebase

يعتبر git merge سهل الاستخدام، غير مدمر، بمعني انه يقوم بحفظ كل التغييرات ورسائل التغيير commit messages كما هي في كلا الفرعين المدمجين ويمكنك الرجوع لأي منها في وقت، وعند وجود اي تعارضات في التغييرات بين الفرعين فانه يتم حلها فقط مره واحده عند الدمج ولا تحتاج لحلها كل مره يتم اضافه تغييرات جديده في الفرع المدمج. ولكن عادة ما ينتج عنه تاريخ تغييرات غير منظم ويزيد الامر سوءا اذا كان يتم الدمج بطريقه دورية كما أنه يتم اضافه رساله دمج commit message إضافية عند دمج اي فرعين. 

,وفي حالة git rebase فإنه ينتج عنه تاريخ تغييرات منظم ونظيف للفرع بحيث يستطيع اي شخص ان يقوم بتتبع التغييرات بدقه وبالترتيب الصحيح لها ولا يقوم بإضافه رساله دمج إضافية عند الدمج، بل يقوم بترتيب الرسائل الموجودة سلفًا في الفرعين المدمجين بحيث تظهران كخط واحد من التغيررات المرتبة. لكن فكرة إعادة كتابة تاريخ التغييرات وخسارة رسائل التغيير الاصلية (commit messages)  للفرع المدمج قد تتسب في مشاكل جمة لاعضاء الفريق في حال تمت مشاركة الفرع معهم، ففهي هذه الحالة قمت انت بتغيير تاريخ التغييرات علي هذا الفرع بحيث اصبح مختلفا عما لديهم. 

استخدم git merge:

  • إذا كنت تريد الاحتفاظ بنفس السجل بدلا من إعادة كتابة الـ history.
  • سيكون التراجع عن التغييرات سهلا. 

استخدم git rebase:

  • إذا كنت تريد الاحتفاظ بسجل git نظيفا.
  • سيكون التراجع عن التغييرات صعبا جدا.

إذا لم تكن تستخدم Git من قبل برجاء إبدأ بإستخدامه من الآن، سوف تشكر نفسك فيما بعد؛ اما إذا كنت مستخدم لـ Git برجاء الالتزام بأفضل الممارسات الممكنة، سوف يشكرك زملائك في العمل بكل تأكيد.

كتب هذا المقال بواسطة الدفعة الثانية في Lintschool، ثم نسقها وجمعها أنس بشندي.

المزيد عن: