Отменить git reset - с нефиксированными файлами в промежуточной области

Я пытаюсь восстановить свою работу. Я тупо сделал git reset --hard, но до этого я сделал только get add . и не делал git commit. Пожалуйста помоги! Вот мой журнал:

MacBookPro:api user$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)

#   modified:   .gitignore
...


MacBookPro:api user$ git reset --hard
HEAD is now at ff546fa added new strucuture for api

Можно ли отменить git reset --hard в этой ситуации?

Ответ 1

Вы должны быть в состоянии восстановить любые файлы, которые вы добавили в индекс (например, как в вашей ситуации, с помощью git add.), Хотя это может быть немного трудоемким. Чтобы добавить файл в индекс, git добавляет его в базу данных объектов, что означает, что его можно восстановить, если сборка мусора еще не произошла. Вот пример того, как это сделать, приведенный в ответе Якуба Наребского:

Однако я попробовал это в тестовом репозитории, и возникла пара проблем - --cached должен быть --cache, и я обнаружил, что он на самом деле не создает каталог .git/lost-found. Тем не менее, следующие шаги работали для меня:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")

Это должно вывести все объекты в базе данных объектов, которые недоступны ни одному из ссылок, ни в индексе, ни через журнал ссылок. Вывод будет выглядеть примерно так:

unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03

... и для каждого из этих BLOB-объектов вы можете сделать:

git show 907b308

Для вывода содержимого файла.


Слишком много продукции?

Обновление в ответ на sehe комментарий ниже:

Если вы обнаружите, что у вас есть много коммитов и деревьев, перечисленных в выходных данных этой команды, вы можете захотеть удалить из выходных данных любые объекты, на которые ссылаются несвязанные коммиты. (Как правило, вы можете вернуться к этим коммитам через reflog в любом случае - нас просто интересуют объекты, которые были добавлены в индекс, но никогда не могут быть найдены с помощью коммита.)

Сначала сохраните вывод команды с помощью:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all

Теперь имена объектов этих недоступных коммитов можно найти с помощью:

egrep commit all | cut -d ' ' -f 3

Таким образом, вы можете найти только деревья и объекты, которые были добавлены в индекс, но не зафиксированы в любой момент, с помощью:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \
  $(egrep commit all | cut -d ' ' -f 3)

Это значительно сокращает количество объектов, которые вы должны рассмотреть.


Обновление: Филип Окли (Philip Oakley) ниже предлагает другой способ сократить количество рассматриваемых объектов, а именно просто рассмотреть самые последние измененные файлы в .git/objects. Вы можете найти их с помощью:

find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort

(Я обнаружил, что find вызов здесь.) Конец этого списка может выглядеть так:

2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b
2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a

В этом случае вы можете увидеть эти объекты с:

git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b
git show de629830603289ef159268f443da79968360913a

(Обратите внимание, что вы должны удалить / в конце пути, чтобы получить имя объекта.)

Ответ 2

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

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

Ответ 3

Благодаря Марку Лонджу я вернул свои вещи!

Сначала я сохранил все хэши в файл:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes

next Я поместил их все (удалив "недостижимое blob" вещь) в списке и поместил все данные в новые файлы... вам нужно выбрать свои файлы и переименовать их снова, что вам нужно... но я только потребовалось несколько файлов. Надеюсь, это поможет кому-то...

commits = ["c2520e04839c05505ef17f985a49ffd42809f",
    "41901be74651829d97f29934f190055ae4e93",
    "50f078c937f07b508a1a73d3566a822927a57",
    "51077d43a3ed6333c8a3616412c9b3b0fb6d4",
    "56e290dc0aaa20e64702357b340d397213cb",
    "5b731d988cfb24500842ec5df84d3e1950c87",
    "9c438e09cf759bf84e109a2f0c18520",
    ...
    ]

from subprocess import call
filename = "file"
i = 1
for c in commits:
    f = open(filename + str(i),"wb")
    call(["git", "show", c],stdout=f)
    i+=1

Ответ 4

@Решение Ajedi32 в комментариях работало для меня именно в этой ситуации.

git reset --hard @{1}

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

Ответ 5

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

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

В отчаянии я попытался нажать CTRL-Z в своем редакторе (LightTable) один раз на каждой открытой вкладке - это, к счастью, восстановил файл на этой вкладке до его последнего состояния до git reset --hard. НТН.

Ответ 6

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

  • Как упоминалось chilicuil, запустите 'git reflog', чтобы идентифицировать там commit hash, который вы хотите вернуться к

  • Как упоминалось akimsko, вы, скорее всего, НЕ захотите выбрать вишневый если только вы не потеряли одно коммит, поэтому вам следует запустить 'git reset --hard

Примечание для пользователей eclipse для egit: Я не смог найти способ выполнить эти шаги в Eclipse с помощью egit. Закрытие Eclipse, выполнение приведенных выше команд из окна терминала, а затем повторное открытие Eclipse работало отлично для меня.

Ответ 7

Это, вероятно, очевидно для профессионалов git, но я хотел это поднять, так как во время моих отчаянных поисков я не увидел, что это поднято.

Я поставил несколько файлов и сделал git reset --hard, немного испугался, а затем заметил, что мой статус показывает, что все мои файлы все еще находятся в стадии подготовки, а также все их удаления не установлены.

На этом этапе вы можете зафиксировать эти поэтапные изменения, если вы не ставите их удаления. После этого вам нужно только набраться смелости, чтобы сделать "git reset --hard" еще раз, что вернет вас к тем изменениям, которые вы поставили и теперь только что совершили.

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

Ответ 8

Вышеуказанные решения могут работать, однако, есть более простые способы исправить это, вместо того, чтобы проходить через git complex undo. Я предполагаю, что большинство git-сбросов происходит с небольшим количеством файлов, и если вы уже используете VIM, это может быть наиболее эффективным решением. Проблема заключается в том, что вы уже должны использовать ViM's упорных-отмены, которые вы должны использовать в любом случае, потому что это дает вам возможность отменить неограниченное количество изменений.

Вот шаги:

  1. В vim нажмите : и введите команду set undodir. Если в вашем .vimrc undodir=~/.vim_runtime/temp_dirs/undodir persistent undo, он покажет результат, подобный undodir=~/.vim_runtime/temp_dirs/undodir.

  2. В вашем репо используйте git log чтобы узнать дату и время последнего совершения

  3. В вашей оболочке перейдите к вашему undodir используя cd ~/.vim_runtime/temp_dirs/undodir.

  4. В этом каталоге используйте эту команду, чтобы найти все файлы, которые вы изменили с момента последнего коммита

    find. -newermt "2018-03-20 11:24:44" \! -newermt "2018-03-23" \( -type f -regextype posix-extended -regex '.*' \) \-not -path "*/env/*" -not -path "*/.git/*"

    Здесь "2018-03-20 11:24:44" - это дата и время последнего коммита. Если дата, в которую вы сделали git reset --hard равна "2018-03-22", то используйте "2018-03-22", а затем "2018-03-23". Это из-за причуды находки, когда нижняя граница является включающей, а верхняя - исключительной. https://unix.stackexchange.com/a/70404/242983

  5. Затем перейдите к каждому из файлов, откройте их в vim и выполните "ранее 20м". Вы можете найти более подробную информацию о "ранее", используя "ч раньше". Здесь earlier 20m означает возвращаться к состоянию файла 20 минут назад, предполагая, что вы сделали git hard --reset, 20 минут назад. Повторите это для всех файлов, которые были выделены из команды find. Я уверен, что кто-то может написать сценарий, который будет сочетать эти вещи.

Ответ 9

Я использую IntelliJ и смог просто просмотреть каждый файл и сделать:

Edit → reload from disk

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

Ответ 10

Запоминание иерархии файлов и использование техники Марка Лонгаира с модификацией Фила Окли дает потрясающие результаты.

По сути, если вы хотя бы добавили файлы в репозиторий, но не зафиксировали его, вы можете восстановить его в интерактивном режиме с помощью "git show", просмотреть журнал и использовать перенаправление оболочки для создания каждого файла (запоминая интересующий вас путь).

НТН!