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

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

  1. Я добавил все файлы, используя git add .
  2. Я тогда совершил
  3. Когда я проверял статус, все еще были файлы, которые не были включены в коммит из надстройки, что было странно
  4. Я снова добавил неотслеживаемые файлы, и на этот раз все заработало
  5. Но я хотел, чтобы все было в одном коммите, поэтому я посмотрел, как выполнить нестандартное то, что я только что сделал
  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'

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

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

$ git status

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

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

$ git add .

Я полагаю, вы использовали то же самое add снова введите команду, как в шаге 1.

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

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

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

$ git reset --hard HEAD^

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

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

$ git reflog

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

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

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

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

Это не приведет к отмене удаления этой фиксации, но приведет к отмене всех поэтапных (но не принятых) изменений из индекса. Первоначально (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> будет печатать содержимое файлов, чтобы вы могли убедиться, что у вас есть нужные объекты. Для больших двоичных объектов вы можете использовать перенаправление ввода-вывода, чтобы записать содержимое в правильное имя файла. Для деревьев вы должны использовать команды 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} это какой-то код, который уникален для файлов, которые у вас были в индексе, тогда он должен дать вам хэши искомых BLOB-объектов:

for b in $(git fsck --lost-found | grep blob | awk '{print $3}'); do git cat-file -p $b | grep -q ${UNIQUE_CODE} && echo $b; done
Другие вопросы по тегам