الدرس 21 · السجل والتكامل
الدمج أم إعادة التأسيس: اختر بالاستعانة بالرسم
نفّذ الدمج وإعادة التأسيس من نسختين متطابقتين لتباعد واحد، وقارن الرسمين والآباء والشجرات، وتعلّم القاعدة الوحيدة التي تحسم الاختيار: من يملك إيداعاتك غيرك؟
- المستوى: متوسط
- قراءة 8 دقائق
- فيديو 6 دقائق
- آخر تحديث
- قبل هذا الدرس: ادمج فرعين تباعد سجلهما, افهم الدمج بالتقديم السريع, أعد تأسيس عمل لم يُدفع بعد
حُفظ التقدّم في هذا المتصفح.
يحمّل التشغيل الفيديو من YouTube (وضع الخصوصية المحسّنة).
ما ستتعلمه
- أن تبدأ الدمج وإعادة التأسيس من نسختين متطابقتين لتكون المقارنة عادلة.
- أن تقرأ أبوي إيداع الدمج، والأب الجديد الوحيد للإيداع المُعاد تأسيسه.
- أن تشرح لماذا قد تنتهي نسختان بالملفات نفسها ولهما سجلان مختلفان.
- أن تختار بقاعدة واحدة: لا تعد كتابة إلا إيداعات لا يملكها غيرك.
قبل البدء
تحتاج إلى نسختين منفصلتين من التباعد الذي بدأ منه الدرس 20، اسماهما gittree-merge وgittree-rebase. في كل نسخة يحمل الفرع feature/signup-form إيداعًا واحدًا لك (سمّه S)، ويحمل الفرع updated-main إيداعًا مختلفًا واحدًا (سمّه N)، وكلاهما بدأ من الإيداع M نفسه، ويشير rescue/signup-before-rebase إلى S. الفرع الخاص محدَّد (مسحوب) ومجلد العمل خالٍ. لا تصنع النسخة الثانية من ناتج الأولى.
كل شيء هنا محلي وضمن الخطة المجانية (يطلب GitTree تسجيل الدخول): دون حساب استضافة أو مزوّد أو إنترنت. كل الهويات خيالية (example.com)، ولا تنفّذ الدرس في مشروع حقيقي.
نفّذ التغييرات في GitTree أو بأوامر Git الأصلية، لا بالطريقتين في النسخة نفسها. القراءة بعد التنفيذ آمنة دائمًا. تسميات القوائم مأخوذة من نصوص GitTree 2.0 نفسها، وشُغّلت الأوامر الأصلية بـ Git 2.43 في نسخ مؤقتة. لم تُشغَّل خطوات GitTree على macOS أو Windows أو Linux؛ تستخدم اختصارات التطبيق Command على macOS حيث تكتب الصفحة Ctrl.
الفكرة وأثر الأفعال
لا تصح المقارنة إلا إذا بدأت النسختان من المراجع والملفات نفسها. إن دمجت أولًا ثم أعدت تأسيس الناتج فقد سألت سؤالًا آخر: صار في نطاق إعادة التطبيق إيداع دمج.
الدمج يحفظ خطّي العمل معًا. يضيف إيداعًا واحدًا جديدًا K له أبوان: S أولًا ثم N. ويحتفظ S وN بمعرّفيهما.
إعادة التأسيس تعيد تطبيق إيداعك فوق N. الناتج S′ فيه التغيير نفسه الذي في S لكن أبوه جديد، ومعرّف الإيداع يتضمن أباه، فيصير لـ S′ معرّف جديد. أما S القديم فلا ينجو إلا لأن فرع الحفظ ما زال يشير إليه.
إن لم يحدث تعارض فتنتهي النسختان بشجرة ملفات واحدة. لكن تطابق الشجرتين لا يعني تطابق السجل: في أحد الرسمين معيّن (diamond) وفي الآخر خط مستقيم، والمعرّفات مختلفة.
اختيار أيهما ليس ذوقًا. إن كان غيرك يملك إيداعاتك فإعادة تطبيقها تكسر نسخه، فادمج. وإن كانت الإيداعات خاصة فإعادة التأسيس آمنة وتعطي سجلًا خطيًا إن فضّله فريقك. لا يجعل أيٌّ منهما الشيفرة أفضل.
في كل نسخة يتحرك الفرع الخاص وحده. لا يُمَس الخادم ولا updated-main ولا main الأصلي.
إعداد حالة المشروع المحددة
اصنع تباعدًا واحدًا ثم انسخه مرتين. ابدأ من نسخة عادية منفصلة من المشروع كما تركه الدرس 18 (main هو إيداع الدمج M). أبقِ gittree-features الأصلي دون مساس، ولا تنفّذ هذا في مستودع المصدر. هوية العرض هي GitTree Demo، demo@example.com، مع إيقاف التوقيع في هذا المستودع وحده.
مدخلات الملفات كاملة
احفظ في المرحلة المحددة فقط بصيغة UTF-8 وLF وسطر نهائي. لا تلصق أسوار Markdown. ترث الملفات الثابتة نقطة البداية؛ لا تستبدل الأصل بنسخة إعادة منفصلة.
index.html — SIGNUP
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">See your work clearly.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
<section aria-labelledby="signup-title">
<h2 id="signup-title">Try the demo form</h2>
<form id="signup-form" novalidate>
<label for="demo-email">Demo email</label>
<input id="demo-email" name="email" type="email" autocomplete="off" aria-describedby="signup-hint">
<p id="signup-hint">Use a fictional example.com address. Nothing is sent.</p>
<button type="submit">Check the address locally</button>
<p id="signup-result" role="status"></p>
</form>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>docs/integration-note.md — DOC_MERGE
# Integration review
This note was written on main while signup work was private.في GitTree
افتح لوحة الأوامر بـ Command+Shift+P (وCtrl+Shift+P على Ubuntu)، واكتب اسم الأمر حرفيًا واخترْه. تستخدم أفعال الفرع المسمّى قائمة النقر بزر الفأرة الأيمن على صفه.
- افتح gittree-merge. ثم اختر علامة تبويب جديدة (New Tab) وافتح gittree-rebase من قائمة الأخيرة (Recent). يحمل كل تبويب اسم مجلده فتميّز بين النسختين.
- في تبويب gittree-merge أبقِ
feature/signup-formمحدَّدًا. انقرupdated-mainبزر الفأرة الأيمن واختر دمج updated-main في feature/signup-form (Merge updated-main into feature/signup-form). - تحت طريقة التسجيل (Record it as) اختر إيداع دمج دائمًا (Always a merge commit)، ثم دمج (Merge) مرة واحدة. للإيداع الجديد أبوان: S أولًا ثم N.
- انتقل إلى تبويب gittree-rebase. ما زال عند S وN كما حفظته. لا تستخدم نسخة الدمج.
- انقر
updated-mainبزر الفأرة الأيمن واختر إعادة تأسيس feature/signup-form على updated-main (Rebase feature/signup-form onto updated-main). اقرأ خيارات إعادة التأسيس هذه (Options for this rebase) وأبقِ الخيارين معطّلين، ثم اختر إعادة تأسيس feature/signup-form (Rebase feature/signup-form) مرة واحدة. - حدّد الإيداع المُعاد تطبيقه. أبوه N ومعرّفه جديد. ما زال
rescue/signup-before-rebaseيسمّي S القديم. - في كل تبويب افتح عرض الملفات (Show Files) ←
index.htmlوdocs/integration-note.md. الصفحة والملاحظة نفسهما في النسختين. ثم ارجع بـ العودة إلى الرسم البياني (Back to Graph). - قارن الرسمين، ثم قل أي قاعدة تحسم الاختيار لهذا الفرع قبل أن تختار ناتجًا. أبقِ النسختين كما هما.
لكل إيداع عادي في الدورة: الملخّص (Summary) هو العنوان المحدد، والوصف (Description) خالٍ، وتبقى الخيارات تعديل الإيداع الأخير وتخطّي الخطّافات وإضافة Signed-off-by ومؤلف مختلف والدفع بعد الإيداع والسماح بإيداع فارغ معطّلة. هذا الدرس لا ينشئ إيداعًا عاديًا.
في الطرفية
ابنِ التباعد في نسخة نظيفة منفصلة من ناتج الدرس 18 (العمل نفسه الذي أجريته في التطبيق، مكتوبًا بأوامر أصلية):
git switch --create feature/signup-formاحفظ صفحة SIGNUP كاملة باسم index.html ثم:
git add -- index.html
git commit --quiet -m "feat: add the local signup demonstration"
git branch rescue/signup-before-rebase
BASE_SHA="$(git rev-parse HEAD~1)"
git switch --quiet --create updated-main "$BASE_SHA"على updated-main احفظ ملاحظة DOC_MERGE كاملة باسم docs/integration-note.md ثم:
git add -- docs/integration-note.md
git commit --quiet -m "docs: add the integration review"
git switch --quiet feature/signup-formBASE_SHA هو الإيداع M الذي ينمو منه الخطان. اصنع الآن النسختين المستقلتين من هذه الحالة بالضبط (cd .. && cp -R gittree-features gittree-merge && cp -R gittree-features gittree-rebase). في نسخة الدمج:
git merge --quiet --no-ff --no-edit updated-main
git rev-list --parents -n 1 HEAD
git rev-parse 'HEAD^{tree}'
git status --shortوفي نسخة إعادة التأسيس التي لم تُمَس:
git rebase --quiet --no-autostash --no-update-refs --no-autosquash updated-main
git rev-list --parents -n 1 HEAD
git rev-parse 'HEAD^{tree}'
git status --shortيطبع git rev-list --parents -n 1 HEAD معرّف الإيداع يليه آباؤه: ثلاثة معرّفات في نسخة الدمج واثنان في نسخة إعادة التأسيس. سطرا HEAD^{tree} معرّف واحد، ولا يطبع git status --short شيئًا في النسختين. أما معرّفا HEAD فمختلفان. ستختلف معرّفاتك عن معرّفات غيرك؛ قارن معرّفاتك ببعضها لا بهذه الصفحة.
لو لم يكن للفرع الخاص إيداع وكان updated-main متقدمًا عليه فقط، لقدّم git merge تقديمًا سريعًا افتراضيًا ولما أنشأ إيداع دمج. هذا مُدخل آخر ونتيجة أخرى؛ اخترها عن قصد، ولا تزيّف دمجًا بأبوين.
النتيجة
أين تنتهي: نسخة الدمج فيها إيداع جديد K أبواه S وN؛ ونسخة إعادة التأسيس فيها S′ أبوه N، وS القديم محفوظ في فرع الحفظ. الشجرتان متطابقتان، والحالتان خاليتان، وmain الأصلي وM والخادم لم يُمَسّوا.
أخطاء شائعة
- افتراض أن الخط المستقيم يعني بقاء معرّف الإيداع القديم. إعادة التأسيس تنشئ إيداعات جديدة دائمًا.
- بدء إعادة التأسيس من ناتج الدمج. هذه تجربة أخرى، وقد يدخل إيداع الدمج في إعادة التطبيق.
- مقارنة معرّفي HEAD وانتظار تطابقهما. قارن الشجرتين بدلًا من ذلك.
- تكرار الدمج أو إعادة التأسيس بعد أن اكتملت العملية.
إن حدث خطأ
لا تتخلّص من أيٍّ من الناتجين لتفرض تطابقهما. إن اختلفت الشجرتان فقارن المراجع الابتدائية وأي حلّ تعارض وأي إيداع زائد، ثم ابدأ من جديد من التباعد المحفوظ. يحفظ فرع الحفظ التاريخ المودَع فقط، لا الملفات غير المودَعة.
اختبر فهمك
أجب عن كل سؤال ثم اقرأ السبب. الأسئلة المعلَّمة «مطلوب» تُحتسب لإكمال الدرس.
0 من 6 صحيحة
أجب عن الأسئلة المطلوبة إجابة صحيحة لتكمل الدرس.
جرى التحقق في هذا المتصفح.
تدريب
اكتب قائمتي الآباء ومعرّفي HEAD ومعرّفي الشجرتين. اشرح لماذا يُتوقع تطابق الشجرتين مع اختلاف معرّفي HEAD. ثم توقّع، دون تنفيذ، ما يفعله الدمج الافتراضي إن لم يكن للفرع الخاص إيداع خاص به.
تأكيد منك أنت: لا يستطيع الموقع رؤية جهازك.
لإكمال الدرس، أجب عن الأسئلة المطلوبة إجابة صحيحة وأكّد تنفيذ التمرين العملي.
خلاصة
- بداية واحدة، وسجلان مختلفان.
- تطابق الشجرتين لا يعني تطابق السجل.
- ادمج إن كان غيرك يملك إيداعاتك. أعد التأسيس للخاصة فقط.
ذو صلة
المصطلحات الجديدة
إعادة التأسيس — Rebase؛ إعادة التطبيق — replay؛ فرع الحفظ — rescue branch.
نص الفيديو
ترجمة التعليق الصوتي الإنجليزي للفيديو، مقطعًا بعد مقطع.
اعرض النص
- دمج أم إعادة تأسيس؟ عمل واحد قد يترك سجلين مختلفين.
- سنجرّب الطريقتين من نقطة البداية نفسها ونقارن.
- لفرعك إيداع واحد، وللفرع المحدَّث إيداع آخر.
- كلاهما نما من الإيداع نفسه، فلا يحتوي أحدهما الآخر.
- أولًا، جهّز التباعد واصنع نسختين متطابقتين.
- لا يصح الاختبار إلا بالمراجع والملفات نفسها في النسختين.
- هذه النسخة الأولى. سندمج فيها.
- وهذه النسخة الثانية. نتركها دون مساس لإعادة التأسيس.
- انقر updated-main بزر الفأرة الأيمن واختر أمر الدمج.
- تحت طريقة التسجيل اختر إيداع دمج دائمًا.
- اختر دمج مرة واحدة وانتظر النتيجة الفعلية.
- للإيداع الجديد أبوان: إيداعك أولًا ثم إيداع updated-main.
- الآن النسخة الثانية. ما زال فيها الإيداعان الأصليان.
- انقر updated-main بالزر الأيمن مجددًا واختر إعادة التأسيس هذه المرة.
- يسمّي الحوار الفرع والهدف. أبقِ الخيارين معطّلين.
- أعد التأسيس مرة واحدة. يعيد Git تطبيق إيداعك فوق updated-main.
- للإيداع المعاد تطبيقه أب جديد، فيأخذ معرّفًا جديدًا.
- الإيداع القديم لم يضِع: فرع الحفظ ما زال يشير إليه.
- قارن الملفات الآن. الصفحة نفسها في النسختين.
- وكذلك ملاحظة الدمج. الملفات نفسها والسجل مختلف.
- انظر إلى الرسمين: معيّن بإيداع دمج، وخط مستقيم.
- فأيهما تستخدم؟ اسأل: من يملك إيداعاتك غيرك؟
- إن كان غيرك يملكها فادمج. إعادة التأسيس ستعيد كتابة سجلهم.
- إن كانت الإيداعات خاصة فإعادة التأسيس آمنة وتعطي خطًا مستقيمًا.
- لا يجعل أيٌّ منهما شيفرتك أفضل. القاعدة عن الملكية.
- الآن أثبت ذلك في الطرفية. أولًا، آباء كل رأس.
- ثلاثة معرّفات لنسخة الدمج: الإيداع وأبواه.
- معرّفان لنسخة إعادة التأسيس: الإيداع وأبوه الوحيد.
- ثم شجرتا الملفات: معرّف واحد مطبوع مرتين. الملفات نفسها.
- لكن معرّفي الإيداعين مختلفان. شجرتان متطابقتان وسجلان مختلفان.
- غيّر المُدخل: لو لم يكن لفرعك إيداع خاص به.
- لقدّم الدمج الافتراضي تقديمًا سريعًا بلا إيداع دمج.
- لا تعد تأسيس فرع يملكه غيرك.
- إن اختلفت الشجرتان فقارن المراجع الابتدائية أولًا.
- لا تحذف ناتجًا لتفرض التطابق.
- تدريب: اكتب الآباء والمعرّفات والشجرات من نسختيك.
- التالي: أعد ترتيب إيداعاتك المحلية وضمّها وأعد صياغتها.