كيفية إرجاع مستودع Git إلى التزام سابق




git-checkout git-reset (20)

الحذر! يمكن أن يؤدي هذا الأمر إلى فقدان محفوظات الالتزام ، إذا قام المستخدم بوضع الالتزام الخطأ عن طريق الخطأ. دائما en احتياطية إضافية من git الخاص بك في مكان آخر فقط في حالة إذا كنت تفعل الأخطاء ، من أنت أكثر أمنا بعض الشيء. :)

لقد واجهت مشكلة مماثلة وأردت العودة إلى الالتزام السابق. في حالتي لم أكن متشبثًا بالاحتفاظ بأحدث التعهدات ومن ثم استخدمت Hard.

هكذا فعلت ذلك:

git reset --hard CommitId && git clean -f

هذا سيعود على المخزون المحلي ، هنا بعد استخدام git push -fسيتم تحديث مستودع عن بعد.

git push -f

كيف أعود من حالتي الحالية إلى لقطة مصنوعة على ارتكاب معين؟

إذا فعلت git log ، git log على الإخراج التالي:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <[email protected]>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <[email protected]>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <[email protected]>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <[email protected]>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

كيف تعود للالتزام من 3 نوفمبر ، أي ارتكبت 0d1d7fc ؟


بدائل اضافية لحلول جيفرومي

حلول Jefromi هي بالتأكيد الأفضل ، ويجب عليك بالتأكيد استخدامها. ومع ذلك ، من أجل اكتمالها ، أردت أيضًا عرض هذه الحلول البديلة الأخرى التي يمكن استخدامها أيضًا في التراجع عن ارتكاب (بمعنى أنك تنشئ التزامًا جديدًا يلغي التغييرات في الالتزام السابق ، تمامًا مثل ما يحدث في git revert ) .

ولكي نكون واضحين ، فإن هذه البدائل ليست هي الطريقة المثلى لعكس الإلتزامات ، حلول Jefromi هي ، لكني فقط أريد أن أشير إلى أنه يمكنك أيضًا استخدام هذه الطرق الأخرى لتحقيق الشيء نفسه مثل git revert .

البديل 1: Resets و Soft Resets

هذا هو نسخة معدلة قليلاً من حل تشارلز بيلي للعودة إلى ارتكاب من قبل التجزئة SHA في جيت؟ :

# Reset the index to the desired commit
git reset --hard <commit>

# Move the branch pointer back to the previous HEAD
git reset --soft [email protected]{1}

# Commit the changes
git commit -m "Revert to <commit>"

هذا يعمل أساسا باستخدام حقيقة أن إعادة تعيين لينة ستترك حالة ارتكاب السابق نظمت في مؤشر / منطقة التدريج ، والتي يمكنك بعد ذلك ارتكاب.

البديل 2: حذف الشجرة الحالية واستبدالها بالواحد الجديد

يأتي هذا الحل من حل svick ل Checkout الالتزام القديم وجعله التزام جديد :

git rm -r .
git checkout <commit> .
git commit

وبالمثل للبديل رقم 1 ، فإن هذا ينتج حالة <commit> في نسخة العمل الحالية. من الضروري إجراء git rm أولاً لأن إلغاء git checkout لن يؤدي إلى إزالة الملفات التي تمت إضافتها منذ <commit> .


عودة نسخة العمل إلى الالتزام الأخير

للرجوع إلى التزام سابق ، مع تجاهل أي تغييرات:

git reset --hard HEAD

حيث يرتكز الأخير في الفرع الحالي

عودة نسخة العمل إلى التزام قديم

للرجوع إلى التزام أقدم من الالتزام الأخير:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft [email protected]{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

تذهب الاعتمادات إلى سؤال مماثل حول ، رجوع إلى ارتكاب بتجزئة SHA في Git؟ .


أفضل خيار بالنسبة لي وربما الآخر هو خيار إعادة تعيين Git:

git reset --hard <commidId> && git clean -f

لقد كان هذا هو الخيار الأفضل بالنسبة لي! انها بسيطة وسريعة وفعالة!

ملاحظة: كما هو مذكور في التعليقات ، لا تفعل ذلك إذا كنت تشارك فرعك مع أشخاص آخرين لديهم نسخ من الإلتزامات القديمة

أيضا من التعليقات ، إذا كنت تريد طريقة أقل "بالز" يمكنك استخدامها

git clean -i


إليك طريقة أبسط بكثير للرجوع إلى التزام سابق (وجعله في حالة غير متعارف عليها ، لكي تفعل بها ما تشاء):

git reset HEAD~1

لذلك ، لا حاجة لمعرفات الالتزام وما إلى ذلك :)


بافتراض أنك تتحدث عن المعلم وعن الفرع المعني (الذي يقال ، قد يكون هذا أي فرع عمل تهتم به):

# Revert local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Revert remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

لقد وجدت الإجابة من في آخر بلوق حذف عن بعد Git ريبو إلى ارتكاب محدد .


قبل الإجابة دعنا نضيف بعض الخلفية ، موضحا ما هو هذا HEAD .

First of all what is HEAD?

HEAD هو ببساطة إشارة إلى الالتزام الحالي (الأحدث) في الفرع الحالي. يمكن أن يكون هناك HEAD واحد فقط في أي وقت معين (باستثناء git worktree ).

يتم تخزين محتوى HEAD داخل .git/HEAD ، ويحتوي على 40 بايت SHA-1 للالتزام الحالي.

detached HEAD

إذا لم تكن على أحدث التزام - وهذا يعني أن HEAD يشير إلى ارتكاب مسبق في التاريخ ، يطلق عليه اسم detached HEAD .

على سطر الأوامر سيبدو هذا - SHA-1 بدلاً من اسم الفرع حيث أن HEAD لا يشير إلى طرف الفرع الحالي:

هناك بعض الخيارات حول كيفية الاسترداد من HEAD مستقل:

git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

هذا سوف الخروج فرع جديد لافتا إلى الالتزام المطلوب. سيخرج هذا الأمر إلى التزام معين.

في هذه المرحلة ، يمكنك إنشاء فرع والبدء في العمل من هذه النقطة على:

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

يمكنك دائما استخدام reflog كذلك. git reflog أي تغيير يقوم بتحديث HEAD وتحقق من إدخال reflog المطلوب سيعيد HEAD إلى هذا الالتزام.

في كل مرة يتم تعديل HEAD سيكون هناك إدخال جديد في reflog

git reflog
git checkout [email protected]{...}

هذا سوف يعيدك إلى ارتكابك المرغوب

git reset HEAD --hard <commit_id>

"حرك" رأسك مرة أخرى إلى الالتزام المرغوب.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • ملاحظة: ( بما أن Git 2.7 ) يمكنك أيضًا استخدام git rebase --no-autostash أيضًا.

يوضح هذا المخطط أي أمر يفعل ما. كما ترى ، هناك reset && checkout تعديل HEAD .


لا شيء هنا يعمل بالنسبة لي بصرف النظر عن هذا المزيج الدقيق:

git reset --hard <commit_hash>
git push origin <branch_name> --force

المفتاح هنا هو دفع الدفع ، عدم ارتكاب أي رسائل / ارتكاب المزيد


لنفترض أن لديك ~/commits-to-revert.txt التالية في ملف نصي اسمه ~/commits-to-revert.txt (استخدمت git log --pretty=oneline للحصول عليها)

fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca

قم بإنشاء برنامج نصي لـ Bash shell لإرجاع كل منها:

#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
    git revert $i --no-commit
done

يعيد هذا كل شيء مرة أخرى إلى الحالة السابقة ، بما في ذلك إنشاء الملفات والدليل ، والحذف ، وارتكبه إلى الفرع الخاص بك وأنت تحتفظ بالسجل ، ولكنك تعود إلى نفس بنية الملف. لماذا لا يملك Git عودة git revert --to <hash> هو أبعد من عندي.


هذا يعتمد كثيرًا على ما تعنيه بـ "العودة".

انتقل مؤقتًا إلى التزام مختلف

إذا كنت تريد الرجوع إليها مؤقتًا ، فاحمق ، ثم عد إلى مكانك ، فكل ما عليك فعله هو التحقق من الالتزام المرغوب:

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

أو إذا كنت ترغب في الإلتزام أثناء وجودك ، فابدأ وقم بإنشاء فرع جديد بينما تكون فيه:

git checkout -b old-state 0d1d7fc32

للرجوع إلى المكان الذي كنت فيه ، ما عليك سوى الاطلاع على الفرع الذي كنت فيه مرة أخرى. (إذا كنت قد أجريت تغييرات ، كما هو الحال دائمًا عند تبديل الفروع ، فسيتعين عليك التعامل معها بالشكل المناسب. يمكنك إعادة تعيينها لرميها ؛ يمكنك خرقها ، سداد الرسوم ، سحق البوب ​​لأخذها معك ؛ يمكنك ارتكاب لهم إلى فرع هناك إذا كنت تريد فرع هناك.)

من الصعب حذف الاحالات غير المنشورة

إذا كنت تريد التخلص من كل ما قمت به منذ ذلك الحين ، فهناك احتمالان. أولاً ، إذا لم تنشر أيًا من هذه الالتزامات ، فعليك ببساطة إعادة تعيين:

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

إذا أخطأت ، فقد ألقيت تغييراتك المحلية بالفعل ، ولكن يمكنك على الأقل العودة إلى المكان الذي كنت فيه من قبل من خلال إعادة التعيين مرة أخرى.

التراجع عن الالتزام مع الالتزام الجديد

من ناحية أخرى ، إذا كنت قد نشرت العمل ، فمن المحتمل أنك لا تريد إعادة تعيين الفرع ، نظرًا لأن ذلك يعيد كتابة السجل بشكل فعال. في هذه الحالة ، يمكنك فعلًا إرجاع الالتزام. مع Git ، يكون للرجوع معنى محدد جدًا: إنشاء التزام باستخدام التصحيح العكسي لإلغائه. بهذه الطريقة لا تقوم بإعادة كتابة أي سجل.

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

يغطي git-revert revert manpage بالفعل الكثير من هذا في وصفه. رابط مفيد آخر هو هذا القسم git-scm.com الذي يناقش الرجوع إلى git .

إذا قررت أنك لا تريد التراجع بعد كل شيء ، فيمكنك التراجع عن التراجع (كما هو موضح هنا) أو إعادة التعيين قبل العودة (راجع القسم السابق).

قد تجد هذه الإجابة مفيدة أيضًا في هذه الحالة:
كيفية نقل HEAD العودة إلى موقع سابق؟ (رأس منفصل)


يمكنك القيام بذلك بواسطة الأمرين التاليين:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

سيزيل التزام Git السابق.

إذا كنت ترغب في الاحتفاظ بالتغييرات ، فيمكنك أيضًا استخدام:

git reset --soft [previous Commit SHA id here]

ثم سيحفظ تغييراتك.


حسنا ، العودة إلى الالتزام السابق في بوابة هو سهل جدا ...

العودة مرة أخرى دون الاحتفاظ بالتغييرات:

git reset --hard <commit>

العودة مرة أخرى مع الاحتفاظ بالتغييرات:

git reset --soft <commit>

قم بشرح الآتي: باستخدام git reset ، يمكنك إعادة التعيين إلى حالة معينة ، فمن الشائع استخدامه باستخدام تجزئة الالتزام كما ترى أعلاه.

ولكن كما ترون الفرق هو استخدام العلمين - --soft و - --soft ، افتراضيًا git reset باستخدام - علم --soft ، ولكن من الممارسات الجيدة دائمًا استخدام العلم ، أشرح كل الأعلام:

--ناعم

لا تغيّر العلامة الافتراضية كما هو موضح ، ولا تحتاج إلى توفيرها ، شجرة العمل ، بل تضيف كل ملفات التغييرات الجاهزة للالتزام ، لذا عليك الرجوع إلى حالة الالتزام التي تتغير التغييرات على الملفات دون ضبطها.

--الصعب

كن حذرا مع هذه العلامة ، فإنه يعيد تعيين شجرة العمل وجميع التغييرات التي تم إجراؤها على الملفات المتعقبة وسوف تختفي جميع!

لقد قمت أيضًا بإنشاء الصورة أدناه التي قد تحدث في الحياة الحقيقية باستخدام git:


الرجوع هو أمر التراجع عن الالتزام.

git revert <commit1> <commit2> 

عينة:

git revert 2h3h23233

إنه قادر على أخذ نطاق من الرأس مثل أدناه. هنا 1 يقول "تعود آخر التزام".

git revert HEAD~1..HEAD

ثم افعل git push


حاول إعادة تعيين الالتزام المرغوب -

git reset <COMMIT_ID>

(للتحقق من استخدام COMMIT_ID git log)

سيؤدي ذلك إلى إعادة تعيين جميع الملفات التي تم تغييرها إلى حالة غير مضافة.

الآن يمكنك checkoutجميع الملفات غير المضافة من قبل

git checkout .

تحقق git logللتحقق من تغييراتك.

تحديث

إذا كان لديك واحد وتلتزم فقط في الريبو الخاص بك ، حاول

git update-ref -d HEAD


لتنظيف دليل المبرمج بالكامل من بعض التغييرات العرضية ، استخدمنا:

git add -A .
git reset --hard HEAD

فقط git reset --hard HEADسوف تتخلص من التعديلات ، لكنها لن تتخلص من الملفات "الجديدة". في حالتهم ، قاموا بطريق الخطأ بطرد مجلد مهم في مكان ما عشوائي ، وتم التعامل مع جميع تلك الملفات على أنها جديدة من قبل Git ، لذا reset --hardلم يتم إصلاحها. من خلال تشغيلها git add -A .مسبقًا ، تتبعها بشكل صريح جميعًا مع git ، ليتم محوها عن طريق إعادة التعيين.


للاحتفاظ بالتغييرات من الالتزام السابق إلى HEAD والانتقال إلى الالتزام السابق ، قم بما يلي:

git reset <SHA>

إذا لم تكن التغييرات مطلوبة من الالتزام السابق إلى HEAD وتجاهل جميع التغييرات فقط ، فنفذ ما يلي:

git reset --hard <SHA>

يمكنك إكمال كل هذه الخطوات الأولية بنفسك والرجوع إلى git repo.

  1. اسحب أحدث إصدار من مستودع التخزين الخاص بك من Bitbucket باستخدام git pull --allالأمر.

  2. قم بتشغيل الأمر git log بـ -n 4 من الجهاز الخاص بك. الرقم بعد تحديد -n عدد الإلتزامات في السجل بدءًا من أحدث التزام في السجل المحلي.

    $ git log -n 4

  3. إعادة تعيين سجل محفوظات المستودع الخاص بك باستخدام git reset --hard HEAD~Nمكان N هو عدد الإلتزامات التي تريد إعادة الرأس إليها. في المثال التالي ، سيتم تعيين الرأس مرة أخرى إلى التزام واحد ، إلى آخر التزام في محفوظات المخزون:

  4. ادفع التغيير إلى git repo باستخدام git push --forceلفرض دفع التغيير.

إذا كنت تريد git repository إلى التزام سابق

git pull --all
git reset --hard HEAD~1
git push --force

إذا كانت الحالة ملحة ، فأنت تريد فقط أن تفعل ما يسأل عنه السائل بطريقة سريعة وقذرة ، بافتراض أن مشروعك تحت دليل "مشروعي":

  1. انسخ الدليل بأكمله وأطلق عليه اسمًا آخر ، مثل "مشروعي - نسخ"

  2. فعل:

    git reset --hard [first-4-letters&numbers-of-commit's-SHA]
    

عندئذ لديك نسختان على نظامك ... يمكنك فحص أو نسخ أو تعديل الملفات ذات الاهتمام ، أو أيا كان ، من الالتزام السابق. يمكنك تجاهل الملفات بالكامل تحت "مشروعي - نسخ" ، إذا كنت قد قررت أن العمل الجديد كان في أي مكان ...

الشيء الواضح إذا كنت ترغب في الاستمرار في حالة المشروع دون التخلص من العمل بالفعل لأن هذا الالتزام المسترجع هو إعادة تسمية الدليل مرة أخرى: حذف المشروع الذي يحتوي على الالتزام المسترد (أو إعطاءه اسم مؤقت) وإعادة تسميته " مشروع بلدي - نسخة "دليل العودة إلى" مشروعي ". ثم على الارجح ارتكاب آخر إلى حد ما في وقت قريب.

Git هو ابتكار رائع ولكن لا يمكنك فقط "التقاطه على الطاير": كما أن الأشخاص الذين يحاولون شرح ذلك كثيرًا ما يفترضون معرفة مسبقة بـ VCS [أنظمة التحكم في الإصدار] والتعمق أكثر في وقت قصير جدًا ، وارتكاب جرائم أخرى ، مثل استخدام عبارات قابلة للتبديل من أجل "التحقق" - بطرق تبدو أحيانًا محسوبة تقريبًا لإرباك المبتدئين.

لإنقاذ نفسك الكثير من الضغط لديك إلى حد كبير لقراءة كتاب على بوابة - أوصي "التحكم في الإصدار مع بوابة" . وإذا كنت تثق بي (أو بالأحرى ندباتي) عندما أقول "يجب أن" ، فهذا يعني أنك قد تفعل ذلك الآن . الكثير من تعقيد Git يأتي من المتفرعة ومن ثم يعيد. لكن من سؤالك لا يوجد سبب يجعل الناس يضطهدونك بالعلوم .

خاصة إذا كان هذا ، على سبيل المثال ، حالة يائسة وكنت مبتدئًا مع Git!

ملاحظة: أحد الفكر الآخر: هو (الآن) في الواقع بسيط جدا للحفاظ على مستودع Git ("الريبو") في دليل آخر غير واحد مع ملفات العمل. هذا يعني أنك لن تضطر إلى نسخ مستودع Git بأكمله باستخدام الحل السريع والقذر أعلاه. انظر إجابة فراير باستخدام - exparate-git-dir here . كن حذرًا ، على الرغم من ذلك: إذا كان لديك مستودع "دليل منفصل" لا تقوم بنسخه ، وستتم إعادة تعيين القرص الصلب ، فسيتم فقد جميع الإصدارات اللاحقة لعملية إعادة التعيين إلى الأبد ، ما لم يكن لديك ، كما ينبغي عليك تمامًا ، إجراء نسخ احتياطي منتظم للمستودع ، ويفضل أن يكون ذلك على السحاب (مثل Google Drive ) من بين أماكن أخرى.


العودة إلى الالتزام الأحدث وتجاهل جميع التغييرات المحلية:

git reset --hard HEAD

نظرًا لأنه يتم دفع التزاماتك عن بُعد ، يجب عليك إزالتها. دعني أفترض أن فرعك يتطور ويتم دفعه على الأصل.

يجب عليك أولاً إزالة التطوير من الأصل:

git push origin :develop (note the colon)

ثم تحتاج إلى تطوير إلى الحالة التي تريدها ، واسمحوا لي أن أفترض التجزئة الالتزام هو EFGHIJK:

git reset --hard EFGHIJK

وأخيرًا ، يتم تطوير الدفع مرة أخرى:

git push origin develop




git-revert