الخلاصة: للتراجع عن آخر commit مع الاحتفاظ بالتغييرات، شغّل git reset --soft HEAD~1 (تبقى التغييرات مجهزة) أو git reset HEAD~1 (تبقى في شجرة العمل). وإذا كان الـ commit مرفوعًا فعلًا، فشغّل git revert HEAD بدلًا منه — ينشئ commitًا جديدًا يُلغيه دون إعادة كتابة التاريخ. هذه الأوامر الثلاثة تغطي تقريبًا كل لحظة “رفعت الـ commit مبكرًا”. وبقية الدليل يتناول كل حالة بأوامر جاهزة للنسخ، ويشرح الفرق بين --soft و--mixed و--hard، ويعرض طريقة الاسترداد إذا سار شيء خطأ. كل أمر أدناه يعمل على أي إصدار حديث من Git على لينكس وmacOS وWindows.
كيف أتراجع عن آخر commit مع الاحتفاظ بالتغييرات؟
الحالة الأكثر شيوعًا: أجريت الـ commit ثم لاحظت خطأً مطبعيًا أو ملفًا ناقصًا أو أدركت أن التغيير ينتمي إلى commit مختلف. لم يُرفع شيء بعد. ألغِ الـ commit وأعد كل شيء إلى مكانه:
# لا يبقى الـ commit في التاريخ — تعود التغييرات إلى منطقة التجهيز
git reset --soft HEAD~1
# تعود التغييرات إلى شجرة العمل (غير مجهزة) بدلًا من ذلك
git reset HEAD~1 HEAD~1 تعني “commit واحدًا قبل المكان الذي يشير إليه HEAD الآن”. بعد أي من الأمرين تبقى ملفاتك كما هي على القرص — المؤشر وحده هو الذي تحرك. تحقق بـ git status: مع --soft تكون التغييرات مجهزة جاهزة لإعادة الـ commit مع الإصلاحات؛ وبدون خيار تكون غير مجهزة فتعدّل بحرية أولًا.
وعادة أكثر أمانًا عندما تريد فقط إضافة ملفات إلى آخر commit: لا تتراجع أصلًا:
git add forgotten-file.txt
git commit --amend --no-edit يستبدل --amend آخر commit في مكانه (بلا تغيير في رسالة الـ commit هنا). لاحظ أن تعديل commit مرفوع يعيد كتابة التاريخ — المزيد أدناه.
ما الفرق بين —soft و—mixed و—hard؟
هذا هو الجزء المستحق للحفظ، لأن الخيار يقرر أين تنتهي تغييراتك — وهل يمكن فقدانها:
| الخيار | أُلغي الـ commit؟ | التغييرات على القرص | مجهزة؟ | الاستخدام المعتاد |
|---|---|---|---|---|
--soft | نعم | محفوظة | نعم | إعادة الـ commit مع إصلاحات صغيرة |
--mixed (الافتراضي) | نعم | محفوظة | لا | إعادة تجميع التغييرات وتجهيزها انتقائيًا |
--hard | نعم | محذوفة | — | رمي العمل بعيدًا تمامًا |
git revert | لا (commit جديد) | محفوظة | — | إلغاء commit مرفوع مسبقًا |
--hard هو الخطر الوحيد: يتجاهل الـ commit والتغييرات معًا. قبل أي reset --hard، خزّن عملك في stash أو فرع:
git branch backup-before-reset # تأمين رخيص
git reset --hard HEAD~1 # الـ commit والتغييرات ذهبا وإذا شغّلت النسخة الخطرة فعلًا فليس كل شيء ضائعًا — git reflog يتذكر أماكن HEAD:
git reflog # اعثر على hash الـ commit الذي فقدته
git reset --hard HEAD@{1} # أو: git reset --hard <hash> يحتفظ الـ reflog بالـ commits المعلقة نحو 90 يومًا افتراضيًا، فجملة “شغّلت hard-reset بالخطأ” قابلة للاسترداد في الغالب إذا تحركت قبل جمع النفايات.
ماذا لو رفعت الـ commit فعلًا؟
إذا كان الـ commit على فرع مشترك (أي شيء غير فرع الميزات الخاص بك)، فلا تعِد كتابة التاريخ. استخدم git revert الذي يحسب التغيير المعاكس ويُنشئ commitًا:
git revert HEAD
git push كل من يسحب يحصل ببساطة على commit جديد يلغي تغييرات القديم. لا force-push، ولا زملاء مكسورون. وإذا احتجت إلغاء سلسلة من الـ commits، فتراجع عن نطاق: git revert --no-commit HEAD~3..HEAD && git commit.
أما البديل — git reset --hard HEAD~1 && git push --force-with-lease — فلا يُقبل إلا على فرع لا يبني عليه أحد غيرك، و--force-with-lease (وليس --force المجردة) هي الصيغة الآمنة الوحيدة لأنها ترفض إذا دفع أحدهم في الأثناء. الـ force-push على الفروع المشتركة هو الطريقة التي تفقد بها الفرق commits ويتوقف سجل CI الغامض عن مطابقة نسخة أي أحد.
كيف أتراجع عن آخر commit مع إبقائه جانبًا؟
أحيانًا يكون الـ commit عملًا جيدًا في عنوان خاطئ — على فرع خاطئ أو مبكرًا جدًا. بدل التراجع عنه، انقله:
git branch stash-commit # أوقف الـ commit على فرع جديد
git reset --hard HEAD~1 # ثم نظّف فرعك الحالي أو خذ الـ commit وحده إلى فرع آخر دون المساس بفرعك الحالي:
git cherry-pick <hash> # وأنت على الفرع الهدف بين reset --soft وcherry-pick وrevert، لا يوجد commit لا يمكنك نقله أو إبطاله — الحيلة هي اختيار “نقل” أم “إلغاء” قبل مدّ اليد نحو أي خيار.
أي تراجع أستخدم؟ دليل قرار سريع
- غير مرفوع، أريد الإصلاح وإعادة الـ commit →
git reset --soft HEAD~1 - غير مرفوع، أريد التجهيز انتقائيًا →
git reset HEAD~1(mixed) - أريد التغييرات تختفي كليًا →
git reset --hard HEAD~1(الـ reflog يعلم، إن ندمت) - مرفوع فعلًا على فرع مشترك →
git revert HEAD - الـ commit ينتمي إلى فرع آخر →
cherry-pick، لا تتراجع
نصيحة تشغيلية أخيرة: إذا وصل commit سيئ فعلًا إلى خادم — خطاف deploy فاشل، أو مشغّل CI يسرف بعد force-push — فالمحطة التالية للبحث هي سجلات الجهاز لا Git. على أي جهاز systemd، يعرض لك journalctl -u <service> -n 100 ماذا جرى ومتى بالضبط؛ وورقة أوامر journalctl عندنا فيها الأنماط الجاهزة للنسخ. وإذا كان سير عملك يتضمن أدوات LLM محلية لمراجعة الفروقات، فقارنّا الخيارين الرئيسيين في Ollama مقابل LM Studio.
— mrsaynothing
— mrsaynothing
ملاحظات ميدانية في الذكاء الاصطناعي وLinux والاستضافة الذاتية.
ناقش هذا المقال على dev.to dev.to ↗
احصل على الشرح التطبيقي التالي بالبريد
رسالة واحدة لكل مقال. أصلح المشكلة وامضِ.
ما هذا؟ورقة أوامر journalctl: تتبع وفلترة سجلات لينكس
أعجبتك هذه الكتابات؟ بناء مثل هذا هو عملي. وظّفني