الوحدة 2 · الفروع والدمج
الـ branches مؤشّرات، والـ HEAD هو أنت
15 دقراءة 4 داملأ الفراغات
الدرس في لمحة
أنشئ الفروع وانتقل بينها وأعد تسميتها واحذفها وأنت تعرف أن كلًا منها مؤشّر متحرّك إلى commit، واخرج بسلام من حالة الـ detached HEAD.
- 1الفرع ورقة لاصقة
- 2إنشاء الفروع والتنقّل بينها
- 3الترتيب والتنظيف
- 4استعارة ملف واحد من فرع آخر
- 5الـ Detached HEAD
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
في أنظمة التحكم في الإصدارات القديمة، كان الـ branch (الفرع) نسخة كاملة من المشروع، بطيئة الإنشاء ومؤلمة الدمج، فكان الناس يتجنّبونها. أما في Git فالفرع يكاد لا يكلّف شيئًا. وهذا يغيّر طريقة عملك: كل فكرة أو إصلاح أو تجربة على موقعك الشخصي يمكن أن تحصل على فرعها الخاص، ورمي الفرع رخيص كإنشائه تمامًا.
الفرع ورقة لاصقة
انظر داخل الـ repository:
cat .git/refs/heads/mainc39be1142d6f0a8e7b1c5d93e2f4a0b6c8d7e912هذا هو فرع main بكامله: ملف يحتوي معرّف commit واحدًا. الـ branch مؤشّر مسمّى ومتحرّك إلى commit. السجلّ الذي خلفه لا يُخزَّن في الفرع؛ بل يُعثر عليه بتتبّع روابط الآباء انطلاقًا من ذلك الـ commit، كما فعلت في الدرس السابق.
فكيف يعرف Git على أيّ فرع أنت؟ بملف صغير آخر:
cat .git/HEADref: refs/heads/mainالـ HEAD مؤشّر إلى مؤشّر. إنه يسمّي فرعًا في العادة، وذلك الفرع يسمّي commit. حين تنشئ commit، ينشئ Git الـ commit الجديد ويجعل الـ commit الحالي أباه، ثم يحرّك الفرع الذي يسمّيه الـ HEAD إلى الـ commit الجديد. الـ HEAD نفسه لا يتغيّر؛ فهو ما زال «على main»، و main هو الذي تقدّم.
لا تحتاج إلى قراءة هذه الملفات يوميًا (وفي الـ repositories الأقدم أو الأكثر نشاطًا قد تُحزم معرّفات الفروع في .git/packed-refs بدلًا من ذلك)، لكن رؤيتها مرة واحدة تزيل الغموض. كل ما في هذا القسم يدور حول تحريك هذه الأوراق اللاصقة على الرسم البياني.
إنشاء الفروع والتنقّل بينها
التغيير التالي في موقعك الشخصي هو footer للموقع. أعطه فرعًا:
git switch -c footerSwitched to a new branch 'footer'الخيار -c ينشئ الفرع عند الـ commit الحالي وينقلك إليه. والصيغة ذات الخطوتين هي git branch footer ثم git switch footer. الآن سجّل بعض العمل:
git add index.html styles.css
git commit -m "Add site footer with contact links"لم يُمسّ main. انتقل إليه فيختفي الـ footer من ملفاتك؛ وانتقل إلى footer مجددًا فيعود:
git switch main # working tree now matches main's snapshot
git switch footer # and now footer's
git switch - # back to whichever branch you were on beforeالانتقال يعيد كتابة الملفات في الـ working tree لتطابق اللقطة الهدف. التغييرات غير المسجّلة تنتقل معك إن لم تتعارض مع الهدف. أما إن كانت ستُكتب فوقها، فيرفض Git الانتقال ويطلب منك أن تسجّلها في commit أو تخبّئها (stash) أولًا. هذا الرفض يحميك؛ فلا تبحث عن طريقة للالتفاف عليه. سجّل العمل في commit، أو انتظر درس الـ stash في القسم الرابع.
الترتيب والتنظيف
git branch # list local branches; * marks the current one
git branch -v # with the commit each points to
git branch -m footer site-footer # rename
git branch -d site-footer # delete, only if its work is merged
git branch -D experiment # force-delete, merged or notيرفض -d حذف فرع لم تُدمج الـ commits الخاصة به في فرعك الحالي (أو في الـ upstream الخاص بالفرع، حين يصبح له upstream)، وهذه شبكة أمان مفيدة. أما -D فيتخطّى هذا الفحص. استخدمه فقط حين تكون متأكّدًا أن العمل غير مرغوب فيه.
سمِّ الفروع بحسب ما تفعله: footer و fix-mobile-nav و projects-grid. كثير من الفرق تضيف بادئة مثل feat/ أو fix/؛ والشرطة المائلة مسموحة في أسماء الفروع.
استعارة ملف واحد من فرع آخر
أحيانًا تريد ملفًا واحدًا من فرع آخر دون بقية عمله. يستطيع git restore القراءة من أي commit:
git restore --source=dark-mode styles.cssهذا يكتب فوق styles.css في الـ working tree بالنسخة الموجودة على dark-mode. افحصه بـ git diff، ثم جهّزه وسجّله في commit على فرعك الحالي. ستظل ترى شروحات قديمة تستخدم git checkout للانتقال والاسترجاع معًا؛ وقد فصل Git 2.23 هاتين المهمّتين إلى git switch و git restore، وهما أصعب في الخلط بينهما.
الـ Detached HEAD
تستطيع أن تجعل الـ HEAD يشير مباشرة إلى commit بدل فرع، لتنظر إلى نسخة قديمة من الموقع:
git switch --detach a1c9d72يحذّرك Git بأنك في حالة detached HEAD (HEAD منفصل). التفقّد آمن تمامًا. الخطر في إنشاء commits هناك: الـ commits الجديدة لا تنتمي إلى أي فرع، فحين تنتقل بعيدًا لا يشير إليها شيء، وتختفي بهدوء من git log.
فرع footer جاهز، و main لم يتحرّك. في الدرس التالي ستجمع الاثنين بعملية merge (دمج).
أهم النقاط
- الـ branch ملف صغير يحمل معرّف commit واحد؛ إنشاؤه لا ينسخ شيئًا ويستغرق أجزاء من الثانية.
- الـ HEAD يسمّي الفرع الذي أنت عليه، وكل commit جديد يحرّك ذلك الفرع إلى الأمام ويتحرّك الـ HEAD معه.
git switch -c <name>ينشئ فرعًا عند الـ commit الحالي وينقلك إليه في خطوة واحدة.- الـ detached HEAD يشير مباشرة إلى commit؛ احفظ أي عمل أنجزته هناك بـ
git switch -c <name>قبل أن تغادر. git restore --source=<branch> <file>ينسخ ملفًا واحدًا من فرع آخر دون الانتقال إليه.