{"id":"l-git-2-1","courseId":"git-github","lang":"ar","kind":"lesson","summary":"أنشئ الفروع وانتقل بينها وأعد تسميتها واحذفها وأنت تعرف أن كلًا منها مؤشّر متحرّك إلى commit، واخرج بسلام من حالة الـ detached HEAD.","html":"<p>في أنظمة التحكم في الإصدارات القديمة، كان الـ branch (الفرع) نسخة كاملة من المشروع، بطيئة الإنشاء ومؤلمة الدمج، فكان الناس يتجنّبونها. أما في Git فالفرع يكاد لا يكلّف شيئًا. وهذا يغيّر طريقة عملك: كل فكرة أو إصلاح أو تجربة على موقعك الشخصي يمكن أن تحصل على فرعها الخاص، ورمي الفرع رخيص كإنشائه تمامًا.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">الفرع ورقة لاصقة</h2>\n<p>انظر داخل الـ repository:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">cat</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> .git/refs/heads/main</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Text</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code>c39be1142d6f0a8e7b1c5d93e2f4a0b6c8d7e912</code></pre></div>\n<p>هذا هو فرع <code dir=\"ltr\">main</code> بكامله: ملف يحتوي معرّف commit واحدًا. الـ <strong>branch</strong> مؤشّر مسمّى ومتحرّك إلى commit. السجلّ الذي خلفه لا يُخزَّن في الفرع؛ بل يُعثر عليه بتتبّع روابط الآباء انطلاقًا من ذلك الـ commit، كما فعلت في الدرس السابق.</p>\n<p>فكيف يعرف Git على أيّ فرع أنت؟ بملف صغير آخر:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">cat</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> .git/HEAD</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">Text</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code>ref: refs/heads/main</code></pre></div>\n<p>الـ <strong>HEAD</strong> مؤشّر إلى مؤشّر. إنه يسمّي فرعًا في العادة، وذلك الفرع يسمّي commit. حين تنشئ commit، ينشئ Git الـ commit الجديد ويجعل الـ commit الحالي أباه، ثم يحرّك الفرع الذي يسمّيه الـ HEAD إلى الـ commit الجديد. الـ HEAD نفسه لا يتغيّر؛ فهو ما زال «على <code dir=\"ltr\">main</code>»، و <code dir=\"ltr\">main</code> هو الذي تقدّم.</p>\n<p>لا تحتاج إلى قراءة هذه الملفات يوميًا (وفي الـ repositories الأقدم أو الأكثر نشاطًا قد تُحزم معرّفات الفروع في <code dir=\"ltr\">.git/packed-refs</code> بدلًا من ذلك)، لكن رؤيتها مرة واحدة تزيل الغموض. كل ما في هذا القسم يدور حول تحريك هذه الأوراق اللاصقة على الرسم البياني.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">إنشاء الفروع والتنقّل بينها</h2>\n<p>التغيير التالي في موقعك الشخصي هو footer للموقع. أعطه فرعًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -c</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> footer</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">Text</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code>Switched to a new branch 'footer'</code></pre></div>\n<p>الخيار <code dir=\"ltr\">-c</code> ينشئ الفرع عند الـ commit الحالي وينقلك إليه. والصيغة ذات الخطوتين هي <code dir=\"ltr\">git branch footer</code> ثم <code dir=\"ltr\">git switch footer</code>. الآن سجّل بعض العمل:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"6\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> add</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> index.html</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> styles.css</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> commit</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -m</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Add site footer with contact links\"</span></span></code></pre></div>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 260\" role=\"img\" aria-labelledby=\"l-git-2-1-t1\"><defs><marker id=\"arrow-l-git-2-1-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-git-2-1-t1\">قبل: الـ commits a1c9 و b2e0 و c39b متتالية؛ main و footer يشيران كلاهما إلى c39b؛ والـ HEAD يشير إلى footer. بعد الـ commit: commit جديد f1a3 يلي c39b؛ تحرّك footer والـ HEAD إلى f1a3؛ وبقي main على c39b.</title>\n  <text class=\"d-label-strong\" x=\"20\" y=\"30\">قبل</text>\n  <circle class=\"d-box\" cx=\"60\" cy=\"90\" r=\"24\"/>\n  <text class=\"d-code\" x=\"60\" y=\"95\" text-anchor=\"middle\">a1c9</text>\n  <circle class=\"d-box\" cx=\"150\" cy=\"90\" r=\"24\"/>\n  <text class=\"d-code\" x=\"150\" y=\"95\" text-anchor=\"middle\">b2e0</text>\n  <circle class=\"d-box\" cx=\"240\" cy=\"90\" r=\"24\"/>\n  <text class=\"d-code\" x=\"240\" y=\"95\" text-anchor=\"middle\">c39b</text>\n  <path class=\"d-line\" d=\"M126 90 L84 90\"/>\n  <path class=\"d-line\" d=\"M216 90 L174 90\"/>\n  <rect class=\"d-box-accent\" x=\"200\" y=\"130\" width=\"80\" height=\"30\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"240\" y=\"150\" text-anchor=\"middle\">main</text>\n  <rect class=\"d-box-accent\" x=\"200\" y=\"170\" width=\"80\" height=\"30\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"240\" y=\"190\" text-anchor=\"middle\">footer</text>\n  <rect class=\"d-box-warn\" x=\"200\" y=\"210\" width=\"80\" height=\"30\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"240\" y=\"230\" text-anchor=\"middle\">HEAD</text>\n  <path class=\"d-line\" d=\"M240 114 L240 130\"/>\n  <text class=\"d-label-strong\" x=\"370\" y=\"30\">بعد git commit</text>\n  <circle class=\"d-box\" cx=\"400\" cy=\"90\" r=\"24\"/>\n  <text class=\"d-code\" x=\"400\" y=\"95\" text-anchor=\"middle\">a1c9</text>\n  <circle class=\"d-box\" cx=\"490\" cy=\"90\" r=\"24\"/>\n  <text class=\"d-code\" x=\"490\" y=\"95\" text-anchor=\"middle\">b2e0</text>\n  <circle class=\"d-box\" cx=\"580\" cy=\"90\" r=\"24\"/>\n  <text class=\"d-code\" x=\"580\" y=\"95\" text-anchor=\"middle\">c39b</text>\n  <circle class=\"d-box-primary\" cx=\"660\" cy=\"90\" r=\"24\"/>\n  <text class=\"d-code\" x=\"660\" y=\"95\" text-anchor=\"middle\">f1a3</text>\n  <path class=\"d-line\" d=\"M466 90 L424 90\"/>\n  <path class=\"d-line\" d=\"M556 90 L514 90\"/>\n  <path class=\"d-line\" d=\"M636 90 L604 90\"/>\n  <rect class=\"d-box-accent\" x=\"540\" y=\"130\" width=\"80\" height=\"30\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"580\" y=\"150\" text-anchor=\"middle\">main</text>\n  <path class=\"d-line\" d=\"M580 114 L580 130\"/>\n  <rect class=\"d-box-accent\" x=\"620\" y=\"170\" width=\"80\" height=\"30\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"660\" y=\"190\" text-anchor=\"middle\">footer</text>\n  <rect class=\"d-box-warn\" x=\"620\" y=\"210\" width=\"80\" height=\"30\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"660\" y=\"230\" text-anchor=\"middle\">HEAD</text>\n  <path class=\"d-line\" d=\"M660 114 L660 170\"/>\n</svg><figcaption>إنشاء الـ commit يحرّك الفرع المرتبط بالـ HEAD</figcaption></figure>\n<p>لم يُمسّ <code dir=\"ltr\">main</code>. انتقل إليه فيختفي الـ footer من ملفاتك؛ وانتقل إلى <code dir=\"ltr\">footer</code> مجددًا فيعود:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"7\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> main</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">      # working tree now matches main's snapshot</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> footer</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">    # and now footer's</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> -</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">         # back to whichever branch you were on before</span></span></code></pre></div>\n<p>الانتقال يعيد كتابة الملفات في الـ working tree لتطابق اللقطة الهدف. التغييرات غير المسجّلة تنتقل معك إن لم تتعارض مع الهدف. أما إن كانت ستُكتب فوقها، فيرفض Git الانتقال ويطلب منك أن تسجّلها في commit أو تخبّئها (stash) أولًا. هذا الرفض يحميك؛ فلا تبحث عن طريقة للالتفاف عليه. سجّل العمل في commit، أو انتظر درس الـ stash في القسم الرابع.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>أنشئ فرعًا حتى وأنت تعمل وحدك</span></p>\n<p>من المغري أن تسجّل الـ commits مباشرة على <code dir=\"ltr\">main</code> في مشروع فردي. لكن تخصيص فرع لكل تغيير يُبقي <code dir=\"ltr\">main</code> جاهزًا للنشر دائمًا: إن جاء الـ footer سيئًا، تحذف الفرع ولا يعرف <code dir=\"ltr\">main</code> عنه شيئًا. وهي أيضًا العادة نفسها التي تحتاجها الـ pull requests في القسم الثالث، فتدرّب عليها الآن والمخاطر منخفضة.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">الترتيب والتنظيف</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"8\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> branch</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">                 # list local branches; * marks the current one</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> branch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -v</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">              # with the commit each points to</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> branch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -m</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> footer</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> site-footer</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">   # rename</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> branch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -d</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> site-footer</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">  # delete, only if its work is merged</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> branch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -D</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> experiment</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">   # force-delete, merged or not</span></span></code></pre></div>\n<p>يرفض <code dir=\"ltr\">-d</code> حذف فرع لم تُدمج الـ commits الخاصة به في فرعك الحالي (أو في الـ upstream الخاص بالفرع، حين يصبح له upstream)، وهذه شبكة أمان مفيدة. أما <code dir=\"ltr\">-D</code> فيتخطّى هذا الفحص. استخدمه فقط حين تكون متأكّدًا أن العمل غير مرغوب فيه.</p>\n<p>سمِّ الفروع بحسب ما تفعله: <code dir=\"ltr\">footer</code> و <code dir=\"ltr\">fix-mobile-nav</code> و <code dir=\"ltr\">projects-grid</code>. كثير من الفرق تضيف بادئة مثل <code dir=\"ltr\">feat/</code> أو <code dir=\"ltr\">fix/</code>؛ والشرطة المائلة مسموحة في أسماء الفروع.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">استعارة ملف واحد من فرع آخر</h2>\n<p>أحيانًا تريد ملفًا واحدًا من فرع آخر دون بقية عمله. يستطيع <code dir=\"ltr\">git restore</code> القراءة من أي commit:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"9\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> restore</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --source=dark-mode</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> styles.css</span></span></code></pre></div>\n<p>هذا يكتب فوق <code dir=\"ltr\">styles.css</code> في الـ working tree بالنسخة الموجودة على <code dir=\"ltr\">dark-mode</code>. افحصه بـ <code dir=\"ltr\">git diff</code>، ثم جهّزه وسجّله في commit على فرعك الحالي. ستظل ترى شروحات قديمة تستخدم <code dir=\"ltr\">git checkout</code> للانتقال والاسترجاع معًا؛ وقد فصل Git 2.23 هاتين المهمّتين إلى <code dir=\"ltr\">git switch</code> و <code dir=\"ltr\">git restore</code>، وهما أصعب في الخلط بينهما.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">الـ Detached HEAD</h2>\n<p>تستطيع أن تجعل الـ HEAD يشير مباشرة إلى commit بدل فرع، لتنظر إلى نسخة قديمة من الموقع:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"10\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --detach</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> a1c9d72</span></span></code></pre></div>\n<p>يحذّرك Git بأنك في حالة <strong>detached HEAD</strong> (HEAD منفصل). التفقّد آمن تمامًا. الخطر في إنشاء commits هناك: الـ commits الجديدة لا تنتمي إلى أي فرع، فحين تنتقل بعيدًا لا يشير إليها شيء، وتختفي بهدوء من <code dir=\"ltr\">git log</code>.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>إنشاء commit في حالة detached HEAD ثم الانتقال بعيدًا</span></p>\n<p>تنتقل إلى commit قديم، وتصلح شيئًا، وتسجّله، ثم تشغّل <code dir=\"ltr\">git switch main</code>، فيبدو أن الإصلاح اختفى. قبل أن تنتقل بعيدًا، شغّل <code dir=\"ltr\">git switch -c old-fix</code> لتضع فرعًا على الـ commit الجديد. وإن كنت قد انتقلت بالفعل، فقد طبع Git معرّف الـ commit الضائع في تحذير؛ والأمر <code dir=\"ltr\">git switch -c old-fix &lt;that-id&gt;</code> ينقذه. والـ reflog في القسم الرابع يجده حتى لو فاتك التحذير.</p>\n</aside>\n<p>فرع <code dir=\"ltr\">footer</code> جاهز، و <code dir=\"ltr\">main</code> لم يتحرّك. في الدرس التالي ستجمع الاثنين بعملية merge (دمج).</p>\n","toc":[{"id":"sec-1","text":"الفرع ورقة لاصقة","level":2},{"id":"sec-2","text":"إنشاء الفروع والتنقّل بينها","level":2},{"id":"sec-3","text":"الترتيب والتنظيف","level":2},{"id":"sec-4","text":"استعارة ملف واحد من فرع آخر","level":2},{"id":"sec-5","text":"الـ Detached HEAD","level":2}],"takeaways":["الـ branch ملف صغير يحمل معرّف commit واحد؛ إنشاؤه لا ينسخ شيئًا ويستغرق أجزاء من الثانية.","الـ HEAD يسمّي الفرع الذي أنت عليه، وكل commit جديد يحرّك ذلك الفرع إلى الأمام ويتحرّك الـ HEAD معه.","<code dir=\"ltr\">git switch -c &lt;name&gt;</code> ينشئ فرعًا عند الـ commit الحالي وينقلك إليه في خطوة واحدة.","الـ detached HEAD يشير مباشرة إلى commit؛ احفظ أي عمل أنجزته هناك بـ <code dir=\"ltr\">git switch -c &lt;name&gt;</code> قبل أن تغادر.","<code dir=\"ltr\">git restore --source=&lt;branch&gt; &lt;file&gt;</code> ينسخ ملفًا واحدًا من فرع آخر دون الانتقال إليه."],"further":[{"title":"Branches in a Nutshell (Pro Git)","url":"https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell"},{"title":"git switch reference","url":"https://git-scm.com/docs/git-switch"},{"title":"git branch reference","url":"https://git-scm.com/docs/git-branch"}],"quiz":[{"q":"<p>أنت على <code dir=\"ltr\">main</code> عند الـ commit ذي المعرّف <code dir=\"ltr\">b2e0</code>، وتشغّل <code dir=\"ltr\">git switch -c footer</code>، ثم تنشئ الـ commit ذا المعرّف <code dir=\"ltr\">f1a3</code>. إلى أين يشير <code dir=\"ltr\">main</code> و <code dir=\"ltr\">footer</code> الآن؟</p>","options":[{"text":"كلاهما يشير إلى <code dir=\"ltr\">f1a3</code>، لأنهما أُنشئا من الـ commit نفسه.","why":"الفروع لا تبقى مرتبطة ببعضها. وحده الفرع الذي يرتبط به الـ HEAD يتحرّك حين تنشئ commit."},{"text":"<code dir=\"ltr\">main</code> يشير إلى <code dir=\"ltr\">f1a3</code> و <code dir=\"ltr\">footer</code> يشير إلى <code dir=\"ltr\">b2e0</code>.","why":"هذا معكوس. أنت انتقلت إلى <code dir=\"ltr\">footer</code>، لذا فهو الذي يتحرّك."},{"text":"لم يتحرّك أيّ منهما؛ فالفروع لا تتحرّك إلا عند الرفع (push).","why":"إنشاء الـ commit يحرّك الفرع الحالي فورًا. أما الرفع فيتعلّق بنسخ الـ commits إلى remote."},{"text":"<code dir=\"ltr\">main</code> ما زال يشير إلى <code dir=\"ltr\">b2e0</code>؛ و <code dir=\"ltr\">footer</code> تحرّك إلى <code dir=\"ltr\">f1a3</code>.","why":"صحيح. كان الـ HEAD مرتبطًا بـ <code dir=\"ltr\">footer</code>، فقدّم الـ commit الجديد <code dir=\"ltr\">footer</code> إلى الأمام وترك <code dir=\"ltr\">main</code> في مكانه."}],"answer":3},{"q":"<p>ماذا يحتوي الملف <code dir=\"ltr\">.git/HEAD</code> وأنت على فرع <code dir=\"ltr\">footer</code>؟</p>","options":[{"text":"<code dir=\"ltr\">ref: refs/heads/footer</code>","why":"صحيح. الـ HEAD يحمل عادةً اسم فرع، لا معرّف commit. وهذه الإحالة غير المباشرة هي ما يسمح للـ commits بتحريك الفرع."},{"text":"المعرّف المكوّن من 40 حرفًا لآخر commit على <code dir=\"ltr\">footer</code>.","why":"هذا ما يحمله ملف الفرع <code dir=\"ltr\">.git/refs/heads/footer</code>. الـ HEAD يشير إلى الفرع، والفرع يشير إلى الـ commit."},{"text":"قائمة بكل الفروع في الـ repository.","why":"الأمر <code dir=\"ltr\">git branch</code> يبني هذه القائمة بقراءة ملفات الفروع. أما الـ HEAD فيخزّن مكانك فقط."}],"answer":0},{"q":"<p>انتقلت إلى commit قديم لتتفقّده، وأجريت إصلاحًا سريعًا وسجّلته في commit. يقول Git إنك في حالة “detached HEAD”. كيف تحتفظ بذلك الـ commit؟</p>","options":[{"text":"شغّل <code dir=\"ltr\">git switch main</code>؛ وسيأتي الـ commit معك.","why":"الانتقال بعيدًا يترك الـ commit خلفك دون فرع يشير إليه. يصبح ضياعه سهلًا، ويُزال في النهاية بعملية تنظيف المهملات (garbage collection)."},{"text":"لا شيء؛ كل commit يُحفظ على <code dir=\"ltr\">main</code> تلقائيًا.","why":"في حالة الـ detached HEAD، لا تنتمي الـ commits الجديدة إلى أي فرع على الإطلاق، وهذا هو الخطر بعينه."},{"text":"شغّل <code dir=\"ltr\">git switch -c old-fix</code> لتضع فرعًا عليه.","why":"صحيح. الفرع الذي يشير إلى الـ commit يجعله قابلًا للوصول، فيصبح آمنًا. ويمكنك دمجه لاحقًا."},{"text":"شغّل <code dir=\"ltr\">git commit --attach</code>.","why":"لا يوجد خيار <code dir=\"ltr\">--attach</code>. ربط العمل بالسجلّ يعني إنشاء فرع عنده."}],"answer":2},{"q":"<p>في فرعك <code dir=\"ltr\">dark-mode</code> ملف <code dir=\"ltr\">styles.css</code> جاهز تريده على <code dir=\"ltr\">footer</code> أيضًا، دون دمج بقية عمل <code dir=\"ltr\">dark-mode</code>. أنت على <code dir=\"ltr\">footer</code>. أيّ أمر يفعل ذلك؟</p>","options":[{"text":"<code dir=\"ltr\">git switch dark-mode styles.css</code>","why":"<code dir=\"ltr\">git switch</code> يبدّل الفروع. ولا يقبل مسارات ملفات."},{"text":"<code dir=\"ltr\">git restore --source=dark-mode styles.css</code>","why":"صحيح. يكتب <code dir=\"ltr\">styles.css</code> من لقطة <code dir=\"ltr\">dark-mode</code> إلى الـ working tree؛ ثم تراجعه وتجهّزه وتسجّله في commit على <code dir=\"ltr\">footer</code>."},{"text":"<code dir=\"ltr\">git branch dark-mode styles.css</code>","why":"هذه الصيغة تحاول إنشاء فرع اسمه <code dir=\"ltr\">dark-mode</code> يبدأ من commit اسمه <code dir=\"ltr\">styles.css</code>، فتفشل."},{"text":"<code dir=\"ltr\">git merge dark-mode -- styles.css</code>","why":"الدمج يجمع دائمًا commits كاملة. ولا توجد طريقة لدمج ملف واحد."}],"answer":1}],"exercise":{"kind":"fill","language":"bash","template":"git switch {{0}} footer          # create the branch and move onto it\ngit add index.html styles.css\ngit commit -m \"Add site footer with contact links\"\ngit switch {{1}}                 # back to main to check it's untouched\ngit branch -m footer {{2}}       # rename to site-footer","blanks":[{"answers":["-c","--create"]},{"answers":["main","-"]},{"answers":["site-footer"]}],"title":"فرع للـ footer","prompt":"<p>املأ الفراغات: أنشئ فرع <code dir=\"ltr\">footer</code> وانتقل إليه بأمر واحد، وسجّل الـ footer في commit، وعُد إلى <code dir=\"ltr\">main</code> لتتأكّد أنه لم يتغيّر، ثم أعد تسمية الفرع إلى <code dir=\"ltr\">site-footer</code>.</p>\n","hints":["يقبل <code dir=\"ltr\">git switch</code> خيارًا ينشئ الفرع أولًا. وهو اختصار لكلمة create.","تستطيع تسمية الفرع الذي تريد العودة إليه، أو استخدام الاختصار الذي يعني الفرع السابق.","<code dir=\"ltr\">git branch -m &lt;old&gt; &lt;new&gt;</code> يعيد تسمية الفرع."],"explanation":"<p><code dir=\"ltr\">git switch -c footer</code> ينشئ <code dir=\"ltr\">footer</code> عند الـ commit الحالي ويربط الـ HEAD به، فيحرّك الـ commit فرع <code dir=\"ltr\">footer</code> ويترك <code dir=\"ltr\">main</code> على حاله. و <code dir=\"ltr\">git switch main</code> (أو <code dir=\"ltr\">git switch -</code> الذي يعني الفرع السابق) يعيد كتابة الـ working tree على لقطة <code dir=\"ltr\">main</code>. و <code dir=\"ltr\">git branch -m footer site-footer</code> يعيد تسمية المؤشّر؛ أما الـ commits فلا تتغيّر إطلاقًا.</p>\n","checkLabels":{}},"words":696,"readMinutes":4}