Як я можу скасувати скидання git - тверда голова ~ 1?


1156

Чи можливо скасувати зміни, викликані наступною командою? Якщо так, то як?

git reset --hard HEAD~1

8
Я написав повне керівництво по відновленню будь-якого втраченого вчинку за допомогою git. У нього навіть є ілюстрації :-) [Перевірте це] [fixLink] [fixLink]: programblings.com/2008/06/07 / ...
webmat

12
--hardвідкидає невідомі зміни. Оскільки вони не відслідковуються за допомогою git, немає можливості відновити їх через git.
Заз


1
Це чудова стаття, яка допоможе вам відновити файли.
Jan Swart

2
Це чудовий ресурс прямо з Github: Як скасувати (майже) що-небудь із Git
jasonleonhard

Відповіді:


1770

Пат Нотц прав. Ви можете повернути зобов’язання, якщо це пройшло протягом кількох днів. git збирає лише сміття приблизно через місяць або близько того, якщо ви прямо не скажете йому прибрати нові краплі.

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

На прикладі ви бачите, що файл2 було видалено в результаті жорсткого скидання, але його було встановлено на місці, коли я скидався через рефлог.


222
Ви можете використовувати "git reset --hard HEAD @ {1}", не потрібно використовувати SHA1. У більшості випадків має бути достатньо використовувати "git reset --hard ORIG_HEAD".
Якуб Нарбський

39
git log -gможе бути трохи приємнішим способом перегляду рефлогу, ніж git reflog.
Dan Molding

60
Є один дуже важливий застереження з цим .. і ось "- тверда" частина. - Жорсткий знімає ваші місцеві невмілі зміни. І ти не можеш повернути їх таким чином (оскільки вони ніде не були вчинені). Я вважаю, що з цим нічого не можна зробити :(
Майкл Андерсон

3
^ Просто для того, щоб ви знали, що можете зберігати свої локальні зміни перед тим, як зробити скидання --hard, а потім просто спливати їх, і ви нічого не втратите! Треба любити git.
Летякман

5
Я вважаю git reflogза краще git log -gпросто тому, що ви отримуєте всю інформацію в одному рядку з sha1, інформацією HEAD і виконуючи повідомлення, всі вишикувані. Набагато простіше читати.
Snowcrash

370

Що ви хочете зробити, це вказати sha1 комісії, до якого ви хочете відновити. Ви можете отримати sha1, вивчивши reflog ( git reflog), а потім зробивши

git reset --hard <sha1 of desired commit>

Але не чекайте занадто довго ... через кілька тижнів git зрештою побачить цю фіксацію як невстановлену та видалить усі краплі.


2
попередження для себе кілька хвилин тому: це скине всі зміни. він не торкнеться файлів, що не відслідковуються.
aexl

175

Відповідь прихована в детальній відповіді вище, ви можете просто зробити:

$> git reset --hard HEAD@{1}

(Див. Вихід git reflog show )


17
Зауважте, що це не рішення, якщо ви зробили будь-які інші зміни репо з часу скидання. Однозначно перегляньте рефлог перед тим, як щось запустити.
forresthopkinsa

2
Випадково скинув моє сховище, подумав, що моя робота втрачена назавжди. Ця відповідь врятувала мені день.
Zaiyang Li

ого! ти справді врятуєш мені день =)
jfcogato

Чудово. Це справді допомогло.
Прашант Бірадар

117

Його можна відновити, якщо Git ще не зібрав сміття.

Ознайомтесь із звинувачуваними зобов'язаннями за допомогою fsck:

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Відновлення висячого комітету за допомогою rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

1
Це дивовижні речі. Життя збережено.
Мохаммад Хашам

Детальне пояснення можна знайти тут: medium.com/@CarrieGuss/… . Матеріали, що рятують життя.
tuan.dinh

49

Якщо вам справді пощастило, як я, ви можете повернутися до свого текстового редактора і натиснути «скасувати».

Я знаю, що це насправді не є правильною відповіддю, але це врятувало мені південної роботи, тому, сподіваюся, це зробить те ж саме для когось іншого!


3
Це насправді дуже гарна порада, багато разів мене врятувало;) І спосіб простіший, ніж робити що-небудь в git ...
severin

3
і дякую вам за все добро, благодатне в цьому цілому світі. Дякую тобі. Дякую тобі. Дякую тобі.
Поїздка

9
Це єдиний спосіб відновити нестандартні зміни у файлах після жорсткого скидання. Врятував мене теж;)
Czarek Tomczak

4
Як додатковий підказку, деякі IDE, як затемнення, також зберігають недавню історію файлів. Таким чином, ви навіть зможете відновити старі зміни після закриття редактора. Це творило чудеса для мене.
Мартін

1
Бог благословить вас Кріс
Адам Уейт

45

наскільки я знаю, --hardбуде відкинуто неспроможні зміни. Оскільки вони не відслідковуються git. але ви можете скасувати discarded commit.

$ git reflog

буде список:

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

де 4bac331знаходитьсяdiscarded commit .

Тепер просто перемістіть голову до цього комітету:

$ git reset --hard 4bac331

34

Приклад випадку IRL:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

2
Звіряча крапля звучить як монстр AD&D!
sbichenko

Дякую @Stian Добре пояснив! Я хотів би додати для інших, хто знайшов цю відповідь, що якщо у вас є більше одного "звисання", це не впевнено, що ви хочете зробити перезавантаження в останньому ряду :)
JimiSweden

git show врятувало деякі мої файли, спасибі тобі чувак!
Вільям

32

У більшості випадків так.

Залежно від стану, у якому знаходилось ваше сховище, коли ви виконували команду, ефекти параметра git reset --hardможуть бути від тривіальної до скасування, до принципово неможливої.

Нижче я перерахував низку різних можливих сценаріїв, і як ви можете їх відновити.

Всі мої зміни були здійснені, але тепер комітетів вже немає!

Зазвичай ця ситуація виникає при запуску git resetз аргументом, як в git reset --hard HEAD~. Не хвилюйтесь, від цього легко відновитись!

Якщо ти просто біг git reset і з цього часу не робили нічого іншого, ви можете повернутися туди, де ви були з цим одноклассником:

git reset --hard @{1}

Це скидає вашу поточну гілку в будь-який стан, в якому вона була до останнього зміни (у вашому випадку, остання зміна гілки буде жорстким скиданням, яке ви намагаєтесь скасувати).

Якщо ви все ж внесли інші зміни до своєї філії з моменту скидання, однолінійка вище не працюватиме. Натомість вам слід запустити, щоб побачити список усіх останніх змін, внесених у вашу філію (включаючи скидання). Цей список буде виглядати приблизно так:git reflog <branchname>

7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit

Знайдіть операцію в цьому списку, яку ви хочете "скасувати". У наведеному вище прикладі це буде перший рядок, той, що говорить "скидання: перехід до HEAD ~". Потім скопіюйте представлення комісії перед (нижче) цією операцією. У нашому випадку це було б master@{1}(або3ae5027 вони обидва представляють одне і те ж зобов’язання) і виконуєтьсяgit reset --hard <commit> щоб повернути поточну гілку до цього коміту.

Я влаштував свої зміни з git add , але ніколи не вчиняв їх. Тепер мої зміни пропали!

Це трохи складніше, щоб відновитись після. мерзотник дійсно є копії файлів , доданих вами, але так як ці копії не були прив'язані до якої - небудь конкретної фіксації ви не можете відновити зміни відразу. Натомість вам потрібно знайти окремі файли в базі даних git та відновити їх вручну. Це можна зробити за допомогою git fsck.

Докладніше про це див. У Скасуванні git reset - твердий з непосланими файлами в області постановки .

У мене в робочому каталозі були змінині файли, які я ніколи не проводив git addі ніколи не робив. Тепер мої зміни пропали!

Ой-ой. Я ненавиджу вам це казати, але вам, мабуть, не пощастило. git не зберігає зміни, які ви не додаєте або не здійснюєте, а відповідно до документації дляgit reset :

- твердий

Скидає індекс і робоче дерево. Будь-які зміни відсліджених файлів у робочому дереві, оскільки <commit>вони відкидаються.

Цілком можливо , що ви могли б бути в змозі відновити ваші зміни з яким - то утилітою відновлення диска або професійної послуги по відновленню даних, але в цей момент, ймовірно , більше проблем , ніж це коштує.


1
Спасибі на мене працював один лайнер, дякую, але мені просто цікаво, що саме це робить "@ {1}"
Стен Баштавенко

1
@StanB Документація тут: git-scm.com/docs/git-rev-parse, в основному вона стосується першого запису релогів у поточній гілці.
Ajedi32

Дякуємо за висвітлення всіх справ. Я не вчиняв і не додавав своїх.
xdhmoore

21

Якщо ви ще не зібрали сміття зі свого сховища (наприклад, використовуючи git repack -dабоgit gc , але зауважте, що збирання сміття також може відбуватися автоматично), то ваше зобов’язання все ще є - воно просто більше не доступне через HEAD.

Ви можете спробувати знайти свою комісію, переглянувши вихідний файл git fsck --lost-found .

Новіші версії Git мають назву "reflog", що представляє собою журнал усіх змін, які вносяться до refs (на відміну від змін, що вносяться до вмісту сховища). Так, наприклад, щоразу, коли ви перемикаєте HEAD (тобто кожен раз, коли ви git checkoutперемикаєте гілки), який буде реєструватися. І, звичайно, ваш git resetтакож маніпулював ГОЛОВОЮ, тому він також був зареєстрований. Ви можете отримати доступ до старих станів ваших записів аналогічно тому, що ви можете отримати доступ до старих станів вашого сховища, використовуючи @знак замість а ~, як git reset HEAD@{1}.

Мені знадобилось певний час, щоб зрозуміти, в чому різниця між HEAD @ {1} та HEAD ~ 1, тому ось невелике пояснення:

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog

Отже, HEAD~1означає "перейти до комісії перед фіксацією, на яку зараз вказує HEAD"HEAD@{1} означає "перейти до зобов'язання, на яке HEAD вказував, перш ніж вказувати, де воно в даний момент вказує".

Це легко дозволить вам знайти втрачене зобов'язання і відновити його.


2
Ще одне пояснення, яке, на мою думку, було б зрозумілішим: HEAD ~ 1 означає перейти до "батька HEAD", тоді як HEAD @ {1} перейти до "повернутися на один крок в історії HEAD"
kizzx2

1
Проблема полягає в тому, що термін "історія" дійсно перевантажений в ДКС. Ще один спосіб виразити - це те, що ~ йде назад у історії фіксування , тоді як @ йде назад у хронологічній чи часовій історії . Але жодна з трьох версій не є особливо хорошою.
Йорг W Міттаг

@ kizzx2 (і Йорг) насправді ці 3 пояснення, якщо їх взяти разом, дуже допомагають - thx
Річард Ле Месюр'є

14

Перш ніж відповісти, давайте додати деяку інформацію, пояснивши, що це 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не вказує на кінчик поточної гілки

введіть тут опис зображення


Кілька варіантів того, як відновитись із відокремленої ГЛАВИ:


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і перевірка потрібного запису відмикання HEADповернеться до цього зобов'язання.

Кожен раз, коли зміниться HEAD, буде новий запис у reflog

git reflog
git checkout HEAD@{...}

Це поверне вас до бажаного завдання

введіть тут опис зображення


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також.


git revert <sha-1>

"Скасувати" заданий діапазон фіксації чи фіксації.
Команда скидання "скасує" будь-які зміни, внесені в дану комісію.
Новий фіксатор з виправленням патча буде здійснено, тоді як оригінальний запис також залишиться в історії.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Ця схема ілюструє, яка команда робить що.
Як ви бачите, там можна reset && checkoutзмінити HEAD.

введіть тут опис зображення


Здається, ваш git reset HEAD --hard <commit_id>приклад взятий із stackoverflow.com/questions/4114095/… - Якщо це так, чи можете ви редагувати в атрибуції?
Роб

12

git reflog

  • Знайдіть свій список sha в списку, потім скопіюйте та вставте його в цю команду:

git cherry-pick <the sha>


1
git-cherry-pick - застосуйте зміни, внесені деякими існуючими комісіями. Я думаю, що це просто і дуже корисно в цьому контексті
Амітеш,

1
всі насправді шукають цього, коли шукають, як відмінити жорсткі зміни скидання. ця відповідь повинна отримати більш високу оцінку
ErenL

@ErenL Я думаю, що я просто зрозумів, людям подобається робити додаткову роботу. ха-ха
ScottyBlades

1
Ось це, ти щойно врятував мені день 🙂
Сильвернус Акубо

11

Я знаю, що це стара тема ... але, оскільки багато людей шукають способи скасувати речі в Git, я все ще думаю, що це може бути хорошою ідеєю продовжувати давати поради тут.

Коли ви робите "git add" або переміщуєте що-небудь вгорі ліворуч донизу ліворуч у git gui, вміст файлу зберігається у крапці, а вміст файлу можливо відновити з цього крапка.

Таким чином, можна відновити файл, навіть якщо він не був зроблений, але він повинен бути доданий.

git init  
echo hello >> test.txt  
git add test.txt  

Тепер блоб створений, але на нього посилається індекс, тому він не буде перерахований з git fsck, поки ми не скинемо його. Тож ми скидаємо ...

git reset --hard  
git fsck  

ви отримаєте звисаючу крапку ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362  

поверне вам вміст файлу "привіт"

Щоб знайти невирішені комісії, я десь підказав підказку.

gitk --all $(git log -g --pretty=format:%h)  

У мене він є інструментом у git gui, і це дуже зручно.


+1. Як згадується в stackoverflow.com/a/21350689/6309 , git fsck --lost-foundможе допомогти.
VonC

7

Якщо ви використовуєте ID-програму JetBrains IDE (все, що базується на IntelliJ), ви можете відновити навіть невмілі зміни, скориставшись їх функцією "Місцева історія".

Клацніть правою кнопкою миші на директорії верхнього рівня у вашому дереві файлів, у контекстному меню знайдіть "Місцева історія" та виберіть "Показати історію". Це відкриє подання, де можна знайти ваші останні зміни, і як тільки ви знайдете редакцію, до якої хочете повернутися, клацніть правою кнопкою миші та натисніть «Повернути».


4

Я щойно зробив жорсткий перезавантаження на неправильному проекті. Що врятувало мені життя - це краєзнавство Eclipse. У IntelliJ Idea, як кажуть, є і її, і, можливо, ваш редактор, варто перевірити:

  1. Тема довідки про затемнення з краєзнавства
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F

1
Краєзнавство Jetbrains CLion - це чудова і збережена для мене робота 2 години :)
Fabian Knapp

3

Зробив крихітний сценарій, щоб трохи легше було знайти фіксацію, яку шукає:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

Так, це може бути значно красивіше з awk або чимось подібним, але це просто, і я просто потребував цього. Ви можете заощадити когось ще 30 секунд.


0

Моя проблема майже схожа. Я не видав файли до входуgit reset --hard .

Вдячно Мені вдалося пропустити всі ці ресурси. Після того як я помітив, що можу просто скасувати (ctrl-z ). 😊 Я просто хочу додати це до всіх відповідей вище.

Примітка. Неможливо ctrl-zвідкрити файли.


0

Це врятувало мені життя: https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c

В основному вам потрібно запустити:

for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done

Потім вручну переживайте біль, щоб переорганізувати файли у потрібну структуру.

Винос: Ніколи не використовуйте, git reset --hardякщо ви повністю не розумієте, як це працює, краще не використовувати його.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.