الدرس 32 · الاستعادة
التعافي من أخطاء بعد الدفع
أصلح خطأً قد يملكه الآخرون بالفعل: فضّل إيداعًا جديدًا، وحين يلزم أن تعيد كتابة فرع تملكه فادفع قسرًا بقفل مثبَّت على رأس الفرع البعيد الذي راجعته بالضبط.
- المستوى: متقدم
- قراءة 7 دقائق
- فيديو 4 دقائق
- آخر تحديث
- قبل هذا الدرس: ادفع الإيداعات وانشر فرعًا, عكس تغيير في تاريخ مشترك, العثور على إيداع ضائع بسجل المراجع (reflog)
حُفظ التقدّم في هذا المتصفح.
يحمّل التشغيل الفيديو من YouTube (وضع الخصوصية المحسّنة).
ما ستتعلمه
- أن تختار بين إصلاح بالإضافة وإعادة كتابة لخطأ مدفوع.
- أن تشرح ما يفحصه القفل ولماذا يهم الإيداع المتوقَّع.
- أن تتوقع رفض قفل قديم وتحافظ على عمل زميل.
- أن تعرف ما يحفظه GitTree قبل الدفع القسري.
قبل البدء
حالتان على خادم تجريبي محلي. على shared دُفع إيداع سيئ وقد يملكه آخرون. وعلى lease دفعت مسودة ثم أعدت كتابتها محليًا، لكن ليو دفع إيداعًا أحدث إلى الفرع نفسه في هذه الأثناء.
كل شيء هنا محلي وضمن الخطة المجانية (يطلب GitTree تسجيل الدخول): دون حساب استضافة أو مزوّد أو إنترنت. كل الهويات خيالية (example.com). لا تنفّذ الدرس في مشروع حقيقي.
نفّذ التغييرات في GitTree أو بأوامر Git الأصلية، لا بالطريقتين في النسخة نفسها. القراءة بعد التنفيذ آمنة دائمًا. تسميات القوائم مأخوذة من نصوص GitTree 2.0 نفسها، وشُغّلت الأوامر الأصلية بـ Git 2.43 في نسخ مؤقتة. لم تُشغَّل خطوات GitTree على macOS أو Windows أو Linux.
الفكرة وأثر الأفعال
إن كان زملاؤك يملكون الإيداع السيئ فأصلحه بإيداع جديد (عكس، الدرس 28) وادفع دفعًا عاديًا: يبقى الخطأ في التاريخ ولا تُبطَل نسخة أحد. ولا تعد كتابة فرع منشور إلا إن كنت تملكه.
يجعل القفل الدفع القسري مشروطًا: لا يستبدل Git الفرع البعيد إلا إن كان ما زال حيث تتوقع. ويسمّي --force-with-lease=<ref>:<commit> الإيداع المتوقَّع. أما --force-with-lease المجرد فيستخدم مرجعك المتتبِّع للبعيد، وgit fetch يحرّك ذلك المرجع، فالجلب ثم الدفع قد يكتب فوق ما نزّلته للتو. ويثبّت GitTree الإيداع المجلوب أخيرًا ويعرضه في حواره ويحتفظ بالرأس المستبدَل تحت refs/ogt/trash.
ولا يقرر القفل هل يحق لك الكتابة فوق عمل زميل. هو يحميك فقط من الكتابة فوق شيء لم تره.
إعداد حالة المشروع المحددة
ابدأ من نسخة عادية منفصلة من ناتج الدرس 18 ومستودع محلي مجرّد جديد خادمًا وحيدًا. RECOVERY_BAD هي ورقة الأنماط السيئة؛ وLEASE_A وLEASE_B وLEASE_REWRITE ثلاث نسخ من ملاحظة.
مدخلات الملفات كاملة
احفظ كل ملف أدناه كما هو بالضبط: ترميز UTF-8 ونهايات أسطر LF وسطر نهائي واحد، دون أسطر أسوار Markdown. والملفات غير المدرجة تبقى بمحتواها في M.
styles.css — RECOVERY_BAD
:root {
color-scheme: light;
--page: #f7f8fa;
--surface: #ffffff;
--text: #f7f8fa;
--link: #154ab5;
--line: #bac4d0;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background: var(--page);
color: var(--text);
font: 1rem/1.6 system-ui, sans-serif;
}
a {
color: var(--link);
}
.site-header,
main,
footer {
width: min(68rem, 100% - 2rem);
margin-inline: auto;
}
.site-header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 1rem;
padding-block: 1rem;
}
.hero {
max-width: 48rem;
padding-block: 3rem;
}
h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
line-height: 1.2;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
gap: 1rem;
}
.feature-card {
padding: 1rem;
border: 1px solid var(--line);
border-radius: 0.75rem;
background: var(--surface);
}
section {
margin-block-end: 2rem;
}
button,
input {
font: inherit;
}
button,
input {
padding: 0.5rem 0.75rem;
}
:focus-visible {
outline: 3px solid var(--link);
outline-offset: 3px;
}
form {
display: grid;
max-width: 28rem;
gap: 0.5rem;
}docs/lease-note.md — LEASE_A
# Private release rehearsal
The reviewed draft is still private.docs/lease-note.md — LEASE_B
# Private release rehearsal
Leo added a review that must not be overwritten.docs/lease-note.md — LEASE_REWRITE
# Private release rehearsal
This alternative draft has not seen Leo's review.في GitTree
افتح لوحة الأوامر بـ Command+Shift+P (وCtrl+Shift+P على Ubuntu).
- ابنِ البروفة كما يبيّن القسم التالي: الإيداع السيئ مدفوعًا إلى
shared، وفرعleaseوعليه إيداع ليو الأحدث في الخادم. - إصلاح بالإضافة. على
sharedانقر الإيداع السيئ بزر الفأرة الأيمن واختر عكس الإيداع (Revert Commit) ثم اضغط دفع (Push). هذا دفع عادي؛ لا تختر دفع قسري آمن (with-lease)…. - قفل قديم. على
private/leaseأعد كتابة المسودة محليًا ليخلو الفرع من الإيداع المدفوع وحاول دفعه بزر الدفع في الشريط. يسأل GitTree أولًا أين يدفع، لأنprivate/leaseيتتبعorigin/leaseباسم مختلف: اختر الدفع إلى origin/lease. ثم يعرض حوار عنوانه «رفض المستودع البعيد private/lease» الخيارات جلب فقط وإعادة تأسيس ثم دفع ودمج ثم دفع ودفع قسري…. - اختر جلب فقط أولًا واقرأ المخطط: في الفرع البعيد الآن إيداع ليو، وليس في إعادة كتابتك. هذا عمل زميل.
- افتح دفع قسري…. يقول حوار «دفع private/lease قسريًا إلى origin/lease؟» إن الإيداعات التي ينقصها فرعك ستُزال من المستودع البعيد، وإن الدفع لا يمضي إلا ما دام البعيد عند الإيداع المعروض، وإن الرأس المستبدَل يُحفظ تحت
refs/ogt/trash. اختر الإلغاء؛ فعمل ليو ليس لك لتستبدله. - أو وفِّق بدل ذلك: إعادة تأسيس ثم دفع يضع مسودتك فوق مسودة ليو، أو اسأله أولًا. وإن نُفّذ دفع قسري فعلًا فيقول الإشعار «اكتمل الدفع القسري. الرأس البعيد المستبدَل محفوظ في …» ويعدّ تراجع الدفع القسري تغييرًا لمستودع بعيد تدفع مجددًا لإرجاعه.
في الطرفية
بعد العكس، على shared:
git revert --no-edit "$BAD_SHA"
git push origin HEAD:shared
git merge-base --is-ancestor "$BAD_SHA" HEAD; echo $?الجواب 0: يبقى الخطأ في التاريخ ولم يُجبَر أحد على إصلاح نسخة.
على private/lease وإيداع ليو في الخادم، جرّب القفل المثبَّت بالإيداع الذي راجعته:
git push --force-with-lease=refs/heads/lease:"$EXPECTED_SHA" origin HEAD:lease; echo $?
git ls-remote origin refs/heads/lease
git status --short ! [rejected] HEAD -> lease (stale info)
error: failed to push some refs to '../origin.git'
1يرفض Git («stale info») وما زال الخادم يسمّي إيداع ليو والحالة خالية. والأمر git push --force-with-lease origin HEAD:lease المجرد يُرفض أيضًا ما دام مرجعك المتتبِّع قديمًا، لكن بعد git fetch origin lease يستبدل الأمر نفسه إيداع ليو، لأن الجلب حرّك المرجع الذي يقارن به. سمِّ الإيداع الذي راجعته، أو وفِّق بإعادة تأسيس.
النتيجة
أين تنتهي: الإيداع السيئ ما زال في تاريخ shared وفوقه عكس دُفع دفعًا عاديًا. وعلى lease رُفض الدفع المثبَّت، وما زال الخادم يحمل إيداع ليو، وإعادة كتابتك سليمة محليًا. ولم يُنفَّذ أي دفع قسري.
أخطاء شائعة
- إعادة كتابة فرع سحبه الآخرون بالفعل مع أن العكس يكفي.
- الجلب ثم الدفع القسري بقفل مجرد، فيثق الآن بما نزّلته للتو.
- اعتبار القفل إذنًا باستبدال إيداع زميل.
- افتراض أن التراجع يستطيع عكس دفع قسري في الخادم.
إن حدث خطأ
إن استبدل دفع قسري الرأس الخطأ فالإيداع المستبدَل محفوظ تحت refs/ogt/trash (وفي الدفع الأصلي في سجل المراجع ونسخة الزميل). أخبر الزميل واستعد الرأس فرعًا وادفعه من جديد باتفاقكما. والدفع المرفوض لم يغيّر شيئًا.
اختبر فهمك
أجب عن كل سؤال ثم اقرأ السبب. الأسئلة المعلَّمة «مطلوب» تُحتسب لإكمال الدرس.
0 من 6 صحيحة
أجب عن الأسئلة المطلوبة إجابة صحيحة لتكمل الدرس.
جرى التحقق في هذا المتصفح.
تدريب
اذكر فحص السلف على shared، ورمز الخروج ورسالة الدفع المثبَّت، والإيداع الذي يعرضه ls-remote للفرع lease، وهل كان القفل المجرد سيُرفض قبل الجلب وبعده.
تأكيد منك أنت: لا يستطيع الموقع رؤية جهازك.
لإكمال الدرس، أجب عن الأسئلة المطلوبة إجابة صحيحة وأكّد تنفيذ التمرين العملي.
خلاصة
- فضّل إيداعًا جديدًا لكل ما قد يملكه الآخرون.
- ثبّت القفل على الإيداع الذي راجعته.
- القفل يحميك لا نية زميلك.
ذو صلة
المصطلحات الجديدة
Lease — قفل; stale info — معلومات قديمة; replaced tip — الرأس المستبدَل.
نص الفيديو
ترجمة التعليق الصوتي الإنجليزي للفيديو، مقطعًا بعد مقطع.
اعرض النص
- دفعت خطأً. ماذا الآن؟
- إن كان الآخرون يملكون الإيداع فأصلحه بإضافة إيداع.
- يقول القفل: استبدل البعيد فقط إن كان ما زال حيث أتوقع.
- لكن الجلب يحرّك ما يتوقعه القفل المجرد.
- فرعان على خادم محلي: shared وlease.
- على shared اعكس الإيداع السيئ.
- ادفع دفعًا عاديًا. بلا فرض.
- يبقى الخطأ في التاريخ ولا يضطر أحد إلى إصلاح نسخة.
- على lease يُرفض الفرع المعاد كتابته.
- اجلب فقط وانظر. إيداع ليو هناك.
- لا يمضي الدفع إلا والبعيد عند هذا الإيداع، ويحفظ الرأس المستبدَل.
- عمل ليو ليس لك لتستبدله. أعد التأسيس عليه أو اسأله.
- في الطرفية فحص السلف على shared صفر.
- سمِّ الإيداع الذي راجعته. يقول Git معلومات قديمة.
- ما زال الخادم يسمّي إيداع ليو.
- القفل المجرد بعد جلب كان سيستبدله.
- التراجع لا يعكس دفعًا قسريًا في الخادم.
- تدريب: اذكر رمز الخروج وإيداع الخادم والحالة.
- التالي: اعمل على فرعين معًا بمجلدات العمل المتعددة.