Как восстановить сброшенный тайник в Git? - PullRequest
1500 голосов
/ 18 сентября 2008

Я часто использую git stash и git stash pop, чтобы сохранить и восстановить изменения в моем рабочем дереве. Вчера у меня были некоторые изменения в моем рабочем дереве, которые я спрятал и вытолкнул, а затем я сделал больше изменений в своем рабочем дереве. Я хотел бы вернуться и просмотреть вчерашние сохраненные изменения, но git stash pop, кажется, удаляет все ссылки на связанный коммит.

Я знаю, что если я использую git stash, то .git / refs / stash содержит ссылку на коммит, использованный для создания тайника. И .git / logs / refs / stash содержит весь тайник. Но эти ссылки исчезли после git stash pop. Я знаю, что коммит все еще находится где-то в моем хранилище, но я не знаю, что это было.

Есть ли простой способ восстановить вчерашнюю ссылку на коммит?

Обратите внимание, что сегодня это не критично для меня, потому что у меня ежедневные резервные копии и я могу вернуться к вчерашнему рабочему дереву, чтобы получить свои изменения. Я спрашиваю, потому что должен быть более легкий путь!

Ответы [ 18 ]

11 голосов
/ 26 мая 2016

Почему люди задают этот вопрос? Потому что они еще не знают или не понимают рефлог.

Большинство ответов на этот вопрос дают длинные команды с параметрами, которые почти никто не запомнит. Таким образом, люди приходят к этому вопросу и копируют в него то, что им нужно, и забывают об этом почти сразу после этого.

Я бы посоветовал всем с этим вопросом просто проверить reflog (git reflog), не намного более того. Как только вы видите этот список всех коммитов, есть сотни способов узнать, какой коммит вы ищете, и выбрать его или создать из него ветку. В процессе вы узнаете о reflog и полезных опциях для различных основных команд git.

10 голосов
/ 04 января 2013

Я хочу добавить к принятому решению еще один хороший способ пройти через все изменения, когда у вас либо нет доступного gitk, либо X для вывода.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

Затем вы получаете все различия для тех хэшей, которые отображаются один за другим. Нажмите «q», чтобы перейти к следующему различию.

9 голосов
/ 22 февраля 2017

Я не смог получить ни одного ответа для работы в Windows в простом командном окне (в моем случае Windows 7) awk, grep и Select-string не были распознаны как команды. Поэтому я попробовал другой подход:

  • первый запуск: git fsck --unreachable | findstr "commit"
  • скопировать вывод в блокнот
  • найти заменить "недоступный коммит" на start cmd /k git show

будет выглядеть примерно так:

start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

  • сохранить как файл .bat и запустить его
  • скрипт откроет кучу командных окон, показывая каждый коммит
  • если вы нашли тот, который искали, запустите: git stash apply (your hash)

может быть не лучшим решением, но у меня сработало

9 голосов
/ 17 мая 2016

Принятый ответ Аристотеля покажет все достижимые коммиты, включая коммиты, не похожие на тайники. Чтобы отфильтровать шум:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3

Это будет включать только коммиты, которые имеют ровно 3 родительских коммита (которые будут иметь тайник), и чье сообщение включает «WIP on».

Имейте в виду, что если вы сохранили свой тайник с сообщением (например, git stash save "My newly created stash"), это переопределит стандартное сообщение "WIP on ...".

Вы можете отобразить больше информации о каждом коммите, например, отобразить сообщение о коммите или передать его git stash show:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
  git log -1 --format=medium --color=always '{}'; echo; \
  git stash show --color=always '{}'; echo; echo" | \
less -R
9 голосов
/ 07 марта 2018

Вы можете получить список всех недоступных коммитов, написав эту команду в терминале -

git fsck --unreachable

Проверить недостижимый хеш коммита -

git show hash

Наконец примените, если найдете спрятанный предмет -

git stash apply hash
4 голосов
/ 26 августа 2015

Восстановил его, выполнив следующие действия:

  1. Определите удаленный хэш-код тайника:

    gitk --all $ (git fsck --no-reflog | awk '/ висячий коммит / {print $ 3}')

  2. Вишневый козел с заначкой:

    git cherry-pick -m 1 $ stash_hash_code

  3. Разрешить конфликты, если они есть, используя:

    git mergetool

Кроме того, у вас могут возникнуть проблемы с сообщением о коммите, если вы используете gerrit. Пожалуйста, сохраните ваши изменения, прежде чем использовать следующие альтернативы:

  1. Используйте hard reset к предыдущему коммиту и затем подтвердите это изменение.
  2. Вы также можете спрятать изменения, перебазировать и подтвердить.
4 голосов
/ 07 ноября 2013

Что я пришел сюда, так это как вернуть тайник, независимо от того, что я проверил. В частности, я спрятал что-то, затем проверил более старую версию, затем выскочил, но тайник был недоступен в тот более ранний момент времени, поэтому тайник исчез; Я не мог просто сделать git stash, чтобы вернуть его обратно в стек. Это сработало для меня:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

Оглядываясь назад, я должен был использовать git stash apply, а не git stash pop. Я делал bisect и у меня был маленький патч, который я хотел применить на каждом bisect шаге. Сейчас я делаю это:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.
0 голосов
/ 27 июля 2018

Я случайно удалил тайник в приложении GitUP. Просто нажмите Ctrl + Z, чтобы отменить его.

Может быть, это кому-нибудь поможет;)

...