git reset
إعادة ضبط HEAD الحالي إلى الحالة المحددة
يُستخدم الأمر 'git reset' للتراجع عن التغييرات بنقل HEAD الفرع الحالي إلى commit محدد. له ثلاثة أوضاع رئيسية: --soft (يُبقي التغييرات مجهّزة)، و--mixed (الافتراضي - يُبقي التغييرات في مجلد العمل)، و--hard (يتخلّص من كل التغييرات). هذا الأمر أساسي للتراجع عن الـ commits وإلغاء تجهيز الملفات وإدارة التاريخ. احذر من 'git reset --hard' لأنه يتخلّص من التغييرات نهائيًا.
الصيغة
git reset [-q] [<tree-ish>] [--] <pathspec>...
git reset [-q] [--pathspec-from-file=<file>] [<tree-ish>]
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]الخيارات
اختيار الخيار المناسب
أوضاع reset: ما الذي يبقى؟
فهم الأوضاع الثلاثة الرئيسية لـ reset وما يحدث لتغييراتك
| الأمر | يتحرك HEAD | منطقة التجهيز | مجلد العمل | استخدمه حين |
|---|---|---|---|---|
--soft | نعم | يبقى (مجهَّزًا) | محفوظ | التراجع عن commit لإعادته مع تغييرات |
--mixed (default) | نعم | يُفرَّغ (غير مجهَّز) | محفوظ | التراجع عن commit للتعديل قبل التجهيز |
--hard | نعم | مُفرَّغ | تضيع تعديلات الملفات المتتبَّعة (وتبقى غير المتتبَّعة) | التخلّص تمامًا من الـ commit وكل التغييرات |
Reset مقابل Revert مقابل Checkout
اختيار أمر التراجع المناسب لحالتك
| الأمر | يعدّل التاريخ؟ | آمن للـ commits المدفوعة؟ | الأنسب لـ |
|---|---|---|---|
git reset | نعم (ينقل الفرع) | لا - يسبب مشكلات | التراجع عن commits محلية لم تُدفع بعد |
git revert | لا (يضيف commit جديدًا) | نعم - آمن للفروع المشتركة | التراجع عن commits مدفوعة على فروع مشتركة |
git checkout -- file | No | نعم | التخلّص من التغييرات غير المحفوظة في ملفات محددة |
إلغاء التجهيز: reset مقابل restore
يقدّم Git الحديث git restore بديلًا لـ reset لإلغاء التجهيز
| الأمر | الغرض | يؤثر في الـ commits؟ | موصى به |
|---|---|---|---|
git reset HEAD file | إلغاء تجهيز ملف | No | الطريقة التقليدية |
git restore --staged file | إلغاء تجهيز ملف | No | الطريقة الحديثة (Git 2.23+) |
git reset | إلغاء تجهيز كل الملفات | No | يعمل جيدًا |
git restore --staged . | إلغاء تجهيز كل الملفات | No | نية أوضح |
أوضاع reset متقدمة
متى تستخدم --merge و--keep بدل --hard
| الأمر | يحافظ على التغييرات المحلية؟ | يتوقف عند التعارض؟ | حالة الاستخدام |
|---|---|---|---|
--hard | لا - يدمّر كل شيء | No | إعادة ضبط كاملة، والتغييرات لا تهم |
--merge | التغييرات غير المجهّزة فقط (وتضيع المجهّزة) | نعم | إلغاء دمج مع إبقاء العمل غير المرتبط به |
--keep | نعم (في الملفات التي لا يمسها reset) | نعم | التراجع عن commit مع إبقاء تعديلات محلية غير مرتبطة |
أمثلة
التراجع عن آخر commit مع إبقاء التغييرات مجهّزة
git reset --soft HEAD~1يُرجع HEAD بـ commit واحد. تبقى تغييرات ذلك الـ commit مجهّزة، جاهزة لحفظها من جديد.
التراجع عن آخر commit مع إبقاء التغييرات في مجلد العمل
git reset HEAD~1الوضع الافتراضي (--mixed). يُرجع HEAD بـ commit واحد. تبقى التغييرات لكنها غير مجهّزة.
التخلّص تمامًا من آخر commit والتغييرات
git reset --hard HEAD~1يُرجع HEAD بـ commit واحد ويتخلّص من كل التغييرات غير المحفوظة في الملفات المتتبَّعة. استخدمه بحذر - العمل غير المحفوظ الضائع لا يُستعاد (أما الـ commit نفسه فيبقى في git reflog).
إلغاء تجهيز ملف محدد
git reset HEAD file.jsيزيل file.js من منطقة التجهيز دون التخلّص من التغييرات. يبقى الملف معدّلًا في مجلد العمل.
أمثلة على سير العمل
git log --oneline -3اعرض الـ commits الأخيرة للتأكد من الـ commit المراد التراجع عنه
git reset --soft HEAD~1تراجع عن الـ commit وأبقِ التغييرات مجهّزة
git statusتحقّق أن التغييرات مجهّزة
git commit -m "Better message"احفظ من جديد برسالة جديدة
git statusاعرض ما هو مجهَّز حاليًا
git reset HEAD unwanted-file.jsألغِ تجهيز ملف أو أكثر
git statusتأكد أن الملف لم يعد مجهّزًا
git commitاحفظ الملفات التي تريدها فقط
git statusراجع ما سيضيع
git stash(اختياري) خبّئ التغييرات احتياطًا
git reset --hard HEAD~1تخلّص من آخر commit ومن كل التغييرات المتتبَّعة (تبقى الملفات غير المتتبَّعة)
git statusتأكد أن مجلد العمل نظيف
git reflogاعثر على hash الـ commit الذي كان قبل reset
git reset --hard abc1234أعد الضبط إلى ذلك الـ hash
git log --onelineتحقّق من استعادة الـ commits
حل المشكلات
fatal: ambiguous argument 'HEAD~1': unknown revision
السبب: أنت على الـ commit الأول - لا يوجد commit سابق تعود إليه
راجع git log. إن لم يكن هناك إلا commit واحد، فلا يمكنك الرجوع أكثر. استخدم git update-ref -d HEAD للبدء من جديد تمامًا.
error: Entry 'app.js' not uptodate. Cannot merge.
السبب: ملف يحتاج --merge أو --keep إلى تغييره فيه تعديلات محلية غير محفوظة، فيُلغى الـ reset
احفظ تغييراتك في commit أو خبّئها أولًا، أو استخدم --hard إن أردت التخلّص منها
استخدمت --hard بالخطأ وفقدت تغييرات
السبب: يتخلّص reset الصارم من كل العمل غير المحفوظ نهائيًا
إن كانت التغييرات محفوظة في commit سابقًا: git reflog لإيجاد الـ commit، ثم git reset --hard <hash>. وإن لم تُحفظ قط: فالأرجح أنها ضاعت إلى الأبد.
نجح reset لكن زميلًا يقول إن التاريخ تعطّل
السبب: أعدت ضبط commits كانت مدفوعة أصلًا إلى فرع مشترك
للفروع المشتركة استخدم git revert. وللإصلاح: git reflog، واعثر على الـ commit الأصلي، ونفّذ reset إليه، ثم ادفع بالإجبار (بالتنسيق مع الفريق).
fatal: ambiguous argument 'HEAD' عند تشغيل git reset HEAD file
السبب: لا commits في المستودع بعد، فـ HEAD غير موجود (أو المسار خاطئ)
احذف HEAD: git reset file.js (أو git rm --cached file.js). تحقّق من المسار الدقيق بـ git status.
نصائح وأخطاء شائعة
أفضل الممارسات
- ✓لا تستخدم git reset أبدًا على commits دُفعت إلى فروع مشتركة - استخدم git revert بدلًا منه
- ✓شغّل دائمًا git status قبل reset لتفهم ما الذي سيتأثر
- ✓فضّل --soft حين تريد إعادة commit مع تعديلات
- ✓استخدم git stash قبل reset --hard إن كنت قد تريد استعادة تغييراتك
- ✓تذكّر أن git reflog يستطيع إصلاح معظم أخطاء reset (للتغييرات المحفوظة في commits)
- ✓استخدم git reset HEAD <file> لإلغاء تجهيز الملفات بدل إعادة ضبط commits كاملة
- ✓فكّر في git restore --staged كبديل حديث لإلغاء تجهيز الملفات
أخطاء متكررة
- ✗استخدام 'git reset --hard' دون إدراك أنه يحذف التغييرات غير المحفوظة نهائيًا. تحقّق دائمًا مرتين قبل استخدام --hard.
- ✗إعادة ضبط commits دُفعت أصلًا إلى مستودع بعيد مشترك. يعيد هذا كتابة التاريخ ويسبب مشكلات للمتعاونين. استخدم 'git revert' بدلًا منه.
- ✗الخلط بين 'git reset' و'git revert'. ينقل reset مؤشر الفرع إلى الخلف؛ وينشئ revert commit جديدًا يلغي التغييرات.
- ✗عدم معرفة أنه يمكنك التعافي من reset سيئ باستخدام 'git reflog' لإيجاد hash الـ commit السابق.
- ✗استخدام 'git reset --hard HEAD' للتخلّص من تغييرات العمل بينما 'git checkout -- .' أو 'git restore .' أنسب.
الأسئلة الشائعة
الناعم يُبقي التغييرات مجهّزة. والمختلط (الافتراضي) يُبقيها في مجلد العمل لكن غير مجهّزة. والصارم يتخلّص من كل شيء. فكّر فيها هكذا: soft = التراجع عن الـ commit فقط، mixed = التراجع عن الـ commit + إلغاء التجهيز، hard = التراجع عن كل شيء.
للتغييرات المحفوظة في commits: نعم، استخدم git reflog لإيجاد hash الـ commit الأصلي ثم نفّذ reset إليه. أما التغييرات غير المحفوظة التي ضاعت بـ --hard: فغالبًا لا، فقد ذهبت نهائيًا.
HEAD~1 يعني «commit واحد قبل HEAD». وHEAD~2 يعني commitين إلى الخلف، وهكذا. ويمكنك أيضًا استخدام hashes الـ commits مباشرة مثل git reset abc1234.
reset للـ commits المحلية التي لم تُدفع بعد - يعيد كتابة التاريخ بنظافة. وrevert للـ commits المدفوعة على الفروع المشتركة - ينشئ commit جديدًا يلغي التغييرات دون إعادة كتابة التاريخ.
استخدم git reset HEAD filename لإلغاء تجهيز ملف محدد. لا يتحرك HEAD ولا يتأثر أي commit، بل يُزال الملف من منطقة التجهيز فقط.
يحذف التغييرات غير المحفوظة نهائيًا. بخلاف التغييرات المحفوظة في commits (القابلة للاستعادة عبر الـ reflog)، لا يمكن استعادة عمل لم يُحفظ قط بعد reset صارم.