الدرس 22 · السجل والتكامل
إعادة ترتيب الإيداعات المحلية وضمّها وإعادة صياغتها وإسقاطها
حوّل خمسة إيداعات خاصة غير مرتبة إلى إيداعين نظيفين: انقل إصلاحًا يعتمد على غيره، وأعد صياغة رسالة، واضمم الخطوات، وأسقط الضجيج وحده، ثم تحقق أن الناتج يحوي الملفات التي قصدتها بالضبط.
- المستوى: متقدم
- قراءة 11 دقيقة
- فيديو 7 دقائق
- آخر تحديث
- قبل هذا الدرس: أعد تأسيس عمل لم يُدفع بعد
حُفظ التقدّم في هذا المتصفح.
يحمّل التشغيل الفيديو من YouTube (وضع الخصوصية المحسّنة).
ما ستتعلمه
- أن تقرأ خطة إعادة التطبيق: الخطوة الأقدم أولًا، وتُطبَّق من الأعلى إلى الأسفل.
- أن تختار الإجراء المناسب: إعادة صياغة أو ضمّ أو ضمّ مع تجاهل الرسالة أو إسقاط.
- أن تنقل خطوة دون أن تكسر الخطوة التي تعتمد عليها.
- أن تتحقق بعد ذلك من الإيداعات الجديدة والملفات وفرع الحفظ.
قبل البدء
فرعك private/signup-polish فيه خمسة إيداعات موجودة على حاسوبك وحده، فوق الإيداع M. مجلد العمل خالٍ، ويشير rescue/before-polish إلى الإيداع الخامس. بالترتيب، الأقدم أولًا:
| الخطوة | الإيداع | ماذا يفعل |
|---|---|---|
| C1 | feat: add signup draft | يضيف نموذج التسجيل |
| C2 | docs: explain signup review | يضيف docs/replay-a.md |
| C3 | docs: explain validation | يضيف docs/replay-b.md |
| C4 | fixup! feat: add signup draft | يصلح تسمية النموذج |
| C5 | chore: temporary note | يضيف docs/temporary-review.md |
كل شيء هنا محلي وضمن الخطة المجانية (يطلب GitTree تسجيل الدخول): دون حساب استضافة أو مزوّد أو إنترنت. كل الهويات خيالية (example.com). لا تنفّذ الدرس في مشروع حقيقي، ولا تعد كتابة إيداعات يملكها غيرك.
نفّذ التغييرات في GitTree أو بأوامر Git الأصلية، لا بالطريقتين في النسخة نفسها. القراءة بعد التنفيذ آمنة دائمًا. تسميات القوائم مأخوذة من نصوص GitTree 2.0 نفسها، وشُغّلت الأوامر الأصلية بـ Git 2.43 في نسخ مؤقتة. لم تُشغَّل خطوات GitTree على macOS أو Windows أو Linux.
الفكرة وأثر الأفعال
إعادة التأسيس التفاعلية خطة لا لعبة ترتيب. يعيد Git تطبيق الإيداعات المدرجة واحدًا واحدًا فوق القاعدة، من أعلى القائمة إلى أسفلها، فالخطوة الأقدم أولًا. ويخبر كل إجراء Git ماذا يفعل بخطوة واحدة:
- اختيار (Pick) يُبقي الإيداع كما هو.
- إعادة صياغة (Reword) يُبقي محتواه ويتيح لك رسالة جديدة.
- ضمّ (Squash) يطوي الإيداع في الإيداع المُبقى فوقه ويتيح لك رسالة واحدة مجمّعة.
- ضمّ مع تجاهل الرسالة (Fixup) يطويه كذلك لكنه يتجاهل رسالته.
- إسقاط (Drop) يترك تغيير الإيداع خارج السجل كليًا.
الترتيب مهم. الخطوة التي تعتمد على غيرها (هنا إصلاح التسمية يحتاج النموذج الذي في C1) يجب أن تبقى تحتها. سيسمح لك المحرر بنقلها فوقها، ثم يتوقف إعادة التطبيق بتعارض. ويرفض GitTree خططًا لا يستطيع Git تنفيذها: خطة تُسقط كل الإيداعات، وضمّ لا إيداع فوقه يُطوى فيه، ورسالة فارغة.
يأخذ كل إيداع معاد التطبيق معرّفًا جديدًا لأن أباه تغيّر. يُعاد كتابة هذا الفرع وحده؛ ويحتفظ فرع الحفظ بالخمسة القدامى. تُعلَّم الإيداعات الموجودة على مستودع بعيد بعبارة «على مستودع بعيد»، وإعادة كتابتها تحتاج تأكيدًا صريحًا. هذا الدرس لا يؤكد ذلك أبدًا.
الخطة التي ستبنيها تحوّل خمسة إيداعات إلى اثنين:
| الخطوة | الإيداع | الإجراء | الناتج |
|---|---|---|---|
| 1 | C1 | إعادة صياغة | feat: complete the local signup form |
| 2 | C4 | ضمّ مع تجاهل الرسالة | مطوي في الخطوة 1 |
| 3 | C3 | اختيار | يبقى؛ هو هدف الضمّ |
| 4 | C2 | ضمّ | docs: explain signup review and validation |
| 5 | C5 | إسقاط | يختفي |
إعداد حالة المشروع المحددة
ابدأ من نسخة عادية منفصلة من المشروع كما تركه الدرس 18. أبقِ gittree-features الأصلي دون مساس. ابنِ الإيداعات الخمسة أدناه على فرع جديد، ملفًا بعد ملف، واحفظ كل نص كامل في خطوته المسمّاة فقط.
مدخلات الملفات كاملة
احفظ في المرحلة المحددة فقط بصيغة 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/replay-a.md — DOC_A
# Local signup review
Review the label and hint together.docs/replay-b.md — DOC_B
# Local validation review
No address leaves this demonstration.index.html — SIGNUP_LABEL
<!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">Fictional email address</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/temporary-review.md — DOC_NOISE
Temporary rehearsal note, deliberately dropped.في GitTree
افتح لوحة الأوامر بـ Command+Shift+P (وCtrl+Shift+P على Ubuntu). تستخدم أفعال الإيداع قائمة النقر بزر الفأرة الأيمن على صفه.
- ابنِ الإيداعات الخمسة وفرع الحفظ كما يبيّن القسم التالي، مع تحديد
private/signup-polishوخلوه. دوّن M والعناوين الخمسة. - انقر M، الإيداع الذي تحت الخمسة، بزر الفأرة الأيمن واختر تعديل السجل (Edit History) ← إعادة تأسيس تفاعلية للإيداعات التي تعلوه… (Interactive Rebase of the Commits Above…). يفتح المحرر بالخطوات الخاصة الخمس، الأقدم أولًا.
- تحت خيارات إعادة التأسيس هذه (Options for this rebase) أبقِ الخيارات الثلاثة معطّلة، ومنها رتّب إيداعات fixup! وsquash! وamend! (Arrange fixup!, squash! and amend! commits). ستنقل الإصلاح بنفسك.
- ركّز على صف C4 واضغط Alt+↑ مرتين، ثم ركّز على C3 واضغط Alt+↑ مرة. يصير الترتيب C1 وC4 وC3 وC2 وC5. الضغط على p أو r أو e أو s أو f أو d على صف مركَّز يعيّن اختيار أو إعادة صياغة أو تحرير أو ضمّ أو ضمّ مع تجاهل الرسالة أو إسقاط.
- اضبط C1 على إعادة صياغة (Reword) واكتب
feat: complete the local signup formفي حقل رسالته. واضبط C4 على ضمّ مع تجاهل الرسالة (Fixup). - أبقِ C3 على اختيار (Pick) واضبط C2 على ضمّ (Squash). تحت الإيداعات المضمومة (Squashed commits) تعرض المجموعة «إيداعان في «docs: explain validation»» رسالة مجمّعة. استبدلها بـ
docs: explain signup review and validation. - اضبط C5 على إسقاط (Drop). اقرأ كل صف والرسالة المجمّعة مرة أخيرة. لا شيء معلَّم «على مستودع بعيد» (On a remote) فلا حاجة إلى تأكيد.
- اختر بدء إعادة التأسيس (Start Rebase) مرة واحدة وانتظر. إن توقفت فتابع من شريط التنبيه، ولا تبدأ الخطة كلها من جديد.
- تحقق من إيداعين جديدين، وإصلاح التسمية في الصفحة، والوثيقتين، وغياب الملاحظة المؤقتة. أبقِ
rescue/before-polishوأبقِ مجلد العمل خاليًا.
لكل إيداع عادي في الدورة: الملخّص (Summary) هو العنوان المحدد، والوصف (Description) خالٍ، وتبقى الخيارات تعديل الإيداع الأخير وتخطّي الخطّافات وإضافة Signed-off-by ومؤلف مختلف والدفع بعد الإيداع والسماح بإيداع فارغ معطّلة.
في الطرفية
ابنِ الإيداعات الخمسة على فرع جديد، واحفظ كل نص كامل في خطوته:
git switch --create private/signup-polishاحفظ SIGNUP باسم index.html ثم:
git add -- index.html
git commit --quiet -m "feat: add signup draft"احفظ DOC_A باسم docs/replay-a.md ثم:
git add -- docs/replay-a.md
git commit --quiet -m "docs: explain signup review"احفظ DOC_B باسم docs/replay-b.md ثم:
git add -- docs/replay-b.md
git commit --quiet -m "docs: explain validation"احفظ SIGNUP_LABEL باسم index.html ثم:
git add -- index.html
git commit --quiet -m "fixup! feat: add signup draft"احفظ DOC_NOISE باسم docs/temporary-review.md ثم:
git add -- docs/temporary-review.md
git commit --quiet -m "chore: temporary note"احفظ الرأس القديم وسرد النطاق، الأقدم أولًا:
git branch rescue/before-polish
BASE_SHA="$(git rev-parse HEAD~5)"
git log --reverse --format=%s "$BASE_SHA"..HEADابدأ الآن إعادة التأسيس التفاعلية (-i صيغة قصيرة لـ --interactive). يفتح Git محررك بقائمة المهام (ستختلف معرّفاتك):
git rebase --interactive --no-autosquash --no-update-refs --no-autostash "$BASE_SHA"pick 1a2b3c4 feat: add signup draft
pick 2b3c4d5 docs: explain signup review
pick 3c4d5e6 docs: explain validation
pick 4d5e6f7 fixup! feat: add signup draft
pick 5e6f708 chore: temporary noteأعد كتابة الأسطر الخمسة لتصير الخطة، مع إبقاء معرّف كل سطر، ثم احفظ:
reword 1a2b3c4 feat: add signup draft
fixup 4d5e6f7 fixup! feat: add signup draft
pick 3c4d5e6 docs: explain validation
squash 2b3c4d5 docs: explain signup review
drop 5e6f708 chore: temporary noteيفتح Git المحرر مرتين أخريين. عند إعادة الصياغة استبدل الرسالة بـ feat: complete the local signup form. وعند الضمّ يعرض الرسالتين معًا؛ استبدلهما بسطر واحد docs: explain signup review and validation. افحص الناتج:
git rev-list --count "$BASE_SHA"..HEAD
git log --reverse --format=%s "$BASE_SHA"..HEAD
git status --short2
feat: complete the local signup form
docs: explain signup review and validationالحالة خالية. index.html هو SIGNUP_LABEL، والوثيقتان موجودتان، وdocs/temporary-review.md غير موجود.
لو وضعت ضمًّا في السطر الأول لتوقف Git فورًا بـ error: cannot 'squash' without a previous commit. أصلح القائمة بـ git rebase --edit-todo ثم git rebase --continue، أو اخرج بـ git rebase --abort. مع --autosquash ينقل Git إيداعات fixup! ويضبط إجراءها عنك؛ يوقفه هذا الدرس ليريك الخطة.
النتيجة
أين تنتهي: إيداعان معاد كتابتهما فوق M، هما «feat: complete the local signup form» و«docs: explain signup review and validation». في الصفحة إصلاح التسمية، والوثيقتان موجودتان والملاحظة المؤقتة غائبة. الإيداعات الخمسة القديمة محفوظة في فرع الحفظ، ومجلد العمل خالٍ.
أخطاء شائعة
- استخدام الإسقاط لإخفاء إيداع قد تحتاجه. تغييره ليس في السجل الجديد إطلاقًا.
- نقل إصلاح فوق الإيداع الذي يصلحه.
- ضمّ الخطوة الأولى، وليس فوقها ما تُطوى فيه.
- بدء الخطة من جديد بعد انتهائها بدل فحص الناتج أولًا.
إن حدث خطأ
قبل البدء يترك إلغاء الفرع كما هو. إن قال GitTree إن الفرع تغيّر منذ فتح المحرر فأغلق المحرر وافتحه مجددًا. إن توقفت إعادة التأسيس فأصلح التعارض أو الرسالة وتابع من شريط التنبيه، أو أوقفها عن قصد. وبعد انتهائها قارن مع rescue/before-polish قبل أن تحاول استعادة أي شيء.
اختبر فهمك
أجب عن كل سؤال ثم اقرأ السبب. الأسئلة المعلَّمة «مطلوب» تُحتسب لإكمال الدرس.
0 من 6 صحيحة
أجب عن الأسئلة المطلوبة إجابة صحيحة لتكمل الدرس.
جرى التحقق في هذا المتصفح.
تدريب
اشرح الخطة C1 وC4 وC3 وC2 وC5 والرسالتين الباقيتين. تحقق: النطاق القديم 5 والجديد 2، والملفات المتوقعة، وغياب الملاحظة. ثم توقّع، دون تنفيذ، لماذا لا يصح نقل C4 فوق C1 ولا ضمّ الخطوة 1.
تأكيد منك أنت: لا يستطيع الموقع رؤية جهازك.
لإكمال الدرس، أجب عن الأسئلة المطلوبة إجابة صحيحة وأكّد تنفيذ التمرين العملي.
خلاصة
- لخطة إعادة التطبيق ترتيب واعتماديات.
- يحتفظ الضمّ برسالتين لتجمعهما أنت، ويتجاهل الضمّ مع تجاهل الرسالة رسالته.
- يزيل الإسقاط التغيير نفسه، فأسقط الضجيج الحقيقي فقط.
ذو صلة
المصطلحات الجديدة
إعادة صياغة — Reword؛ ضمّ — squash؛ ضمّ مع تجاهل الرسالة — fixup؛ إسقاط — drop؛ خطة إعادة التطبيق — replay plan.
نص الفيديو
ترجمة التعليق الصوتي الإنجليزي للفيديو، مقطعًا بعد مقطع.
اعرض النص
- خمسة إيداعات غير مرتبة تصير إيداعين نظيفين، بأمان.
- إعادة التأسيس التفاعلية خطة: قائمة خطوات، الأقدم أولًا.
- يعيد Git تطبيق القائمة من الأعلى إلى الأسفل فوق قاعدة.
- لكل خطوة إجراء: اختيار أو إعادة صياغة أو ضمّ أو ضمّ مع تجاهل الرسالة أو إسقاط.
- أولًا، ابنِ خمسة إيداعات خاصة وفرع حفظ.
- ثلاثة منها عمل حقيقي، وواحد إصلاح، وآخر ضجيج مؤقت.
- انقر الإيداع الذي تحتها بزر الفأرة الأيمن وافتح تعديل السجل.
- اختر إعادة تأسيس تفاعلية للإيداعات التي تعلوه.
- يعرض المحرر الخطوات الخمس، الأقدم أولًا.
- أبقِ الخيارات الثلاثة معطّلة. سننقل الإصلاح بأنفسنا.
- مكان الإصلاح بعد الإيداع الذي يصلحه مباشرة. انقله لأعلى مرتين.
- الآن انقل ملاحظة التحقق فوق ملاحظة المراجعة.
- الترتيب الآن: واحد، أربعة، ثلاثة، اثنان، خمسة.
- اضبط الخطوة الأولى على إعادة صياغة واكتب الرسالة الجديدة.
- اضبط خطوة الإصلاح على ضمّ مع تجاهل الرسالة. تُهمَل رسالتها.
- أبقِ ملاحظة التحقق، واضمم ملاحظة المراجعة فيها.
- يعرض الضمّ الرسالتين. اكتب رسالة واحدة للزوج.
- أسقط الملاحظة المؤقتة. لن ينجو تغييرها.
- اقرأ كل صف مرة أخيرة. لا شيء على مستودع بعيد.
- اختر بدء إعادة التأسيس مرة واحدة وانتظر انتهاءها.
- في المخطط الآن إيداعان فوق القاعدة.
- لكليهما معرّف جديد. الخمسة القدامى على فرع الحفظ.
- افتح الصفحة: إصلاح التسمية موجود. والضجيج اختفى.
- الآن الخطة نفسها في الطرفية، بـ git rebase -i.
- يفتح Git قائمة المهام. الأقدم أولًا وكلها على اختيار.
- أعد كتابة الأسطر لتصير خطتنا: إعادة صياغة، ضمّ بلا رسالة، اختيار، ضمّ، إسقاط.
- يطلب Git الرسالتين. اكتب سطرًا لكل منهما.
- عدّ الإيداعات فوق القاعدة: اثنان.
- اسرد العناوين. هذان ما كتبناه.
- الحالة خالية، والملاحظة المؤقتة اختفت.
- غيّر المُدخل: ضع الضمّ في الخطوة الأولى.
- لا شيء فوقه ليُطوى فيه، فيرفض Git.
- أو انقل الإصلاح فوق إيداعه: تتوقف إعادة التطبيق بتعارض.
- إن توقفت فأصلح وتابع. أو أوقفها ولن يتغير شيء.
- فرع الحفظ ما زال يحمل إيداعاتك الخمسة الأصلية.
- لا تعد كتابة إيداعات يملكها غيرك.
- تدريب: اشرح الخطة ولماذا لا تصلح الخطوة الأولى للضمّ.
- التالي: حلّ التعارضات حين يتوقف دمج أو إعادة تأسيس.