Восстановление файлов, которые были добавлены в индекс, но затем удалены git reset

я добавил некоторые файлы в индекс, но затем по ошибке удалил их с git reset --hard. Как их восстановить? Вот что случилось:--7-->

  1. я добавил Все файлы с помощью git add .
  2. Я тогда совершил
  3. когда я проверил статус, все еще были файлы, которые не были включены в фиксацию из добавления, что было странно
  4. я снова добавил неотслеженные файлы, и на этот раз это сработало
  5. но я хотел, чтобы все было в 1 single commit поэтому я посмотрел, как unstage то, что я только что совершил
  6. Я git reset --hard HEAD^ - плохая идея, очевидно, все файлы были удалены
  7. Итак, я использовал git reflog найти, где я остановился
  8. затем я использовал git reflog ______ чтобы вернуться к моему последнему обязательству.
  9. затем я использовал git reset HEAD чтобы отменить фиксацию (что я должен был сделать изначально), но файлы, которые я добавил (см. выше) после фиксации, все еще отсутствовали.

как мне получить эти файлы назад?

2 ответов


во-первых, сделайте полную резервную копию своего репозитория Git!

когда вы git add файл, git создаст blob из содержимого этого файла и добавит его в свою базу данных объектов (.git/objects/??/*).

давайте посмотрим на ваши команды, одну за другой:

я добавил Все файлы с помощью git add .

$ git add .

это добавит все файлы, содержащиеся в текущем каталоге и его подкаталогах, в базу данных объектов Git. Неотслеженные файлы, соответствующие шаблонам из .gitignore файлы не будут добавлены. Также будут записаны файлы дерева. Пожалуйста, посмотрите конец моего ответа.

я тогда совершил

$ git commit -m'added all files'

это напишет новый объект фиксации в базу данных объектов. Эта фиксация будет ссылаться на одно дерево. Дерево ссылается на blobs (файлы) и другие деревья (подкаталоги).

когда я проверил статус, все еще были файлы, которые не были включены в фиксации от добавления, что было странно

$ git status

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

я снова добавил неотслеженные файлы, и на этот раз это сработало

$ git add .

я предполагаю, что вы использовали тот же снова, как в шаге 1.

но я хотел, чтобы все было в 1 одиночной фиксации, поэтому я посмотрел, как чтобы распутать то, что я только что совершил

я расскажу вам лучший способ в конце этого ответа, который не требует от пользователя выдавать потенциально опасный reset

я использовал git reset --hard HEAD^ - плохая идея, очевидно, все файлы были удалены

$ git reset --hard HEAD^

эта команда установит ваше текущее рабочее дерево и индекс точно в commit HEAD^ (вторая-последняя фиксация). Другими словами, он будет отбрасывать любые локальные незафиксированные изменения и перемещение указателя ветви назад на одну фиксацию. Он не касается неотслеженных файлов.

Итак, я использовал git reflog, чтобы найти, где я остановился

$ git reflog

это показывает последние коммиты, которые были недавно проверены (идентичны git reflog HEAD). Если вы укажете имя ветви, он покажет вам последние коммиты, на которые эта ветвь указала недавно.

тогда я использовал git reflog __ перейти назад к моему последнему обязательству.

не уверен насчет этого. git reflog является (в основном) командой только для чтения и не может использоваться для "возврата" к коммитам. Вы можете использовать его только для поиска коммитов ветви (или HEAD) указал на.

затем я использовал git reset HEAD для отмены фиксации (что я должен был сделать изначально), но файлы, которые я добавил (см. выше) после фиксации, все еще отсутствовали. глава $ ГИТ сброс

это не будет unstage эта фиксация, но она будет отменять все поэтапные (но незафиксированные) изменения из индекса. Первоначально (1-й шаг), вы хотели сказать git reset HEAD^ (или git reset --mixed HEAD^) - это оставит ваше рабочее дерево нетронутым, но установите индекс в соответствии с деревом, на которое указывает фиксация с именем HEAD^.


теперь, чтобы вернуть ваши файлы, вы должны использовать git fsck --full --unreachable --no-reflog. Он будет сканировать все объекты в базе данных объектов Git и выполнять анализ достижимости. Вы хотите искать blob объекты. Там также должно быть tree объект, описывающий состояние после вашего второго git add .

git cat-file -p <object hash> будет печатать содержимое файлов, так что вы можете проверить, что у вас есть правильные объекты. Для blobs можно использовать перенаправление ввода-вывода для записи содержимого в правильное имя файла. Для деревьев, вы должны использовать команды git (git read-tree). Если это всего лишь несколько файлов, вам лучше записать их непосредственно в файлы.


несколько заметок здесь:

если вы хотите добавить файлы до последней фиксации (или редактировать его сообщение фиксации), вы можете просто использовать git commit --amend. Это в основном обертка вокруг git reset --soft HEAD^ && git commit -c HEAD@{1}.

кроме того, это почти никогда не хорошая идея, чтобы использовать git add .. Обычно вы хотите использовать его только в первый раз, когда создаете новый репозиторий. Лучшие альтернативы git add -u, git commit -a, который будет этап все изменения в отслеживаемых файлов. Чтобы отслеживать новые файлы, лучше указать их эксплицитно.


у меня была аналогичная проблема, но у меня было много болтающихся капель и деревьев в моем РЕПО, поэтому я закончил фильтрацию с grep вывод всех болтающихся капель и печать тех, которые соответствуют. Предполагая ${UNIQUE_CODE} - это некоторый код, уникальный для файлов, которые у вас были в индексе, тогда это должно дать вам хэши блобов, которые вы ищете:

for b in $(git fsck --lost-found | grep blob | awk '{print }'); do git cat-file -p $b | grep -q ${UNIQUE_CODE} && echo $b; done