Как восстановить потерянный тайник в Git?

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

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

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

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

Комментарии к вопросу (3)
Решение

Как только вы узнаете хэш сброшенного вами тайника, вы можете применить его в качестве тайника:

git stash apply $stash_hash

Или вы можете создать для него отдельную ветку с помощью

git branch recovered $stash_hash

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

Поиск хэша

Если вы только что открыли его, и терминал всё ещё открыт, у вас всё ещё будет значение хэша, выведенное командой git stash pop на экран (спасибо, Dolda).

В противном случае вы можете найти его с помощью этой программы для Linux, Unix или Git Bash для Windows:

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

...или с помощью Powershell для Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

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

Самый простой способ найти нужный вам stash-коммит - это, вероятно, передать этот список в gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

...или смотрите ответ от emragins, если используете Powershell для Windows.

Это запустит браузер репозитория, показывающий вам каждый коммит в репозитории за все время, независимо от того, доступен он или нет.

Вы можете заменить gitk на что-то вроде git log --graph --oneline --decorate, если вы предпочитаете красивый график на консоли, а не отдельное GUI приложение.

Чтобы обнаружить коммиты из тайника, ищите сообщения о коммитах такой формы:

          WIP на somebranch: commithash Some old commit message

Примечание: Сообщение о фиксации будет в таком виде (начиная с "WIP on") только в том случае, если вы не предоставили сообщение, когда делали git stash.

Комментарии (23)

Если вы не't закройте терминал, просто взгляните на результаты в Git тайник поп и вы'll имеет ID объекта за тайник. Это обычно выглядит так:

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

(Обратите внимание, что в Git тайник падение также производит ту же линию.)

Чтобы получить эту заначку обратно, просто запустите ветке git ТМП 2cae03e, и вы'll получить это в качестве филиала. Для преобразования его в тайник, выполните:

git stash apply tmp
git stash

Имея его в качестве филиала также позволяет свободно манипулировать ею, например, для вишни-забрать его или слить его.

Комментарии (10)

Просто хотел сказать, что это дополнение к принятому решению. Это было'т очевидным для меня, когда я впервые попробовал этот метод (возможно это надо было), но применять тайник из хэш-значения, просто использовать "и в Git тайник применить <окрошка> и":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Когда я был новичок в Git, это было'т ясно для меня, и я был пробуя различные комбинации и"ГИТ-шоу и", "в ГИТ применяться и", то "патч" и т. д.

Комментарии (1)

Чтобы получить список заначек, которые находятся в вашем хранилище, но не доступен больше:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

Если вы дали название своей заначки, замены "НП" в -грэп=НЗП на конец командной с частью Вашего сообщения, например-грэп=тесселяции`.

Команда применение grep К и"НП" и так по умолчанию сообщение на тайник в виде НЗП на mybranch: [предыдущая фиксации-хэш] сообщение из предыдущей фиксации.`

Комментарии (7)

Я только что создал команду, которая помогла мне найти потерянный тайник:

for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less

Она перечисляет все объекты в дереве .git/objects, находит те, которые имеют тип commit, а затем показывает сводку по каждому из них. С этого момента остается только просмотреть коммиты, чтобы найти подходящий "WIP на работе: 6a9bb2" ("work" - это моя ветка, 619bb2 - недавний коммит).

Замечу, что если бы я использовал "git stash apply" вместо "git stash pop", у меня бы не было этой проблемы, а если бы я использовал "git stash save message", то коммит было бы легче найти.

Обновление: С идеей Натана это стало короче:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
Комментарии (0)

git fsck --unreachable | grep commit должен показать sha1, хотя список, который он возвращает, может быть довольно большим. git show покажет, тот ли это коммит, который вам нужен.

git cherry-pick -m 1 объединит коммит с текущей веткой.

Комментарии (1)

Если вы хотите restash потерянный тайник, нужно найти хеш потерянные заначку в первую очередь.

Как Аристотель Pagaltzis предложил `ГИТ проверки должны помочь вам.

Лично я использую лог-все мой псевдоним, который покажет мне каждый коммит (извлекаемые совершает), чтобы иметь лучшее представление о ситуации :

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

Вы можете сделать еще более быстрого поиска, если вы'вновь глядя только на "НЗП на" сообщения.

Как только вы знаете свой метод SHA1, вы просто изменить свой заначку reflog, чтобы добавить старую заначку :

git update-ref refs/stash ed6721d

Вы'будете, вероятно, предпочитают иметь соответствующее сообщение Так

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

И вы'Лл еще хотите использовать это в качестве псевдонима :

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1
Комментарии (3)

Окна эквивалент PowerShell с помощью гифок:

гифок-все $(ЖКТ проверке fsck --нет-reflog | выбрать строки с "(висячие фиксации )(.*)&и" | %{ $_.Линии.Сплит(&#39; &#39;)[2] })

Нет, наверное, более эффективный способ сделать это в одну трубу, но это делает работу.

Комментарии (0)

Мне понравилось Аристотелю'ы подход, но ничего'т, как с помощью гифок... как я'м использоваться, чтобы использовать Git из командной строки.

Вместо этого, я взял висящий нарушает и вывести код в файл diff для обзора в моем редакторе кода.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

Теперь вы можете загрузить полученный дифференциал/txt файл (его в домашнюю папку) на ваш редактор TXT и увидеть фактический код и в результате ша.

Затем просто использовать

git stash apply ad38abbf76e26c803b27a6079348192d32f52219
Комментарии (0)

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

git fsck --unreachable

Проверить недоступных фиксации хэш -

git show hash

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

git stash apply hash
Комментарии (0)

Почему люди задают этот вопрос? Потому что они Дон'т знаю, или понять reflog.

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

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

Комментарии (3)

В OSX с Git В2.6.4, я просто случайно в Git тайник капля, потом я нашла ее через следующие шаги

Если вы знаете имя притон затем использовать:

$ Git для выполнения fsck --недоступен | грэп фиксации | вырезать -с 20- | команды xargs Git для шоу | grep -Б 6-а 2 <имя заначки>

в противном случае вы найдете ID от результата вручную с:

$ Git для выполнения fsck --недоступен | грэп фиксации | вырезать -с 20- | команды xargs Git в шоу

Затем, когда вы найдете фиксация-код нажмите заначку ГИТ применяются {фиксация-ИД}

Надеюсь, что это помогает кто-то быстро

Комментарии (0)

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

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

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

Затем вы получаете все дифференциалы для этих хэшей отображаются одна за другой. Пресс 'м' чтобы добраться до следующего сравнения.

Комментарии (0)

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

  • первый запуск: ГИТ проверки --недоступен | findstr команды на "фиксации"в
  • скопировать вывод в блокнот
  • найти замены "недоступен совершить" с `запустить команду cmd /K в ГИТ показать

будет выглядеть так:

`пуск команду cmd /K в ГИТ показать 8506d235f935b92df65d58e7d75e9441220537a4 запустить команду cmd /K в ГИТ показать 44078733e1b36962571019126243782421fcd8ae запустить команду cmd /K в ГИТ показать ec09069ec893db4ec1901f94eefc8dc606b1dbf1 запустить команду cmd /K в ГИТ показать d00aab9198e8b81d052d90720165e48b287c302e``

  • сохранить как .bat файл и запустить его
  • скрипт будет открывать кучу окон, показывая каждый коммит
  • если вы нашли один вы'вновь ищу команду: в Git тайник применить (хэш)

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

Комментарии (1)

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

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 родительских коммитов (что заначка будет), и сообщение, которое включает в себя и"НЗП на&quot&;.

Имейте в виду, что если вы сохранили свой тайник с посланием (например, в Git тайник сохранить "Мой вновь созданный тайник" в), это будет переопределить значение по умолчанию "по НЗП на...на" сообщение.

Можно просмотреть более подробную информацию о каждой фиксации, например, отобразить сообщение или же передать его в Git тайник покажу:

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
Комментарии (0)

Мой любимый-это один-лайнер:

git log --oneline  $( git fsck --no-reflogs | awk '/dangling commit/ {print $3}' )

Это в принципе та же идея, что этот ответ, но намного короче. Конечно, можно еще добавить `--графа, чтобы получить дерево-как дисплей.

Когда вы нашли фиксацию в списке, обратиться с

git stash apply THE_COMMIT_HASH_FOUND

Для меня, используя --не-reflogs указывают на то, что потерял в "копилке", но--недостижимый (как во многих других ответов) не.

Запустить его на bash git, когда вы находитесь под Windows.

Кредиты: детали из перечисленных выше команд берутся из https://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf

Комментарии (0)

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

$ 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 тайник применить " не " в Git тайник поп. Я был делаешь пополам а был маленький патч, который я хотел применить на каждом пополам шаг. Теперь я'м делаю это:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.
Комментарии (2)

Извлекают его с помощью следующих шагов:

  1. Идентификации удаленного заначку хэш-кода:

гифок-все $( ЖКТ проверке fsck --нет-reflog | на awk '/висячие фиксации/ {печати $3}' )

  1. Вишня выбрать заначке:

мерзавец вишня-пык-М 1 $stash_hash_code

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

в Git mergetool

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

  1. Использовать жесткий сброс с предыдущего коммита, а затем подтвердить это изменение.
  2. Вы также можете спрятать изменения, перебазировать и вновь.
Комментарии (1)