Восстановление после случайного git commit -a после добавления патча (git add -p)

git git-commit

48 просмотра

1 ответ

Ранее сегодня я находился в процессе разделения большого коммита git на несколько коммитов меньшего размера, и поэтому, как обычно, я создал новую ветку, сделал a git reset HEAD^и приступил git add -pк интерактивному выбору фрагментов этого большого коммита для разделения на первый из этих коммитов меньшего размера. , Я потратил 20-30 минут на выбор нужных строк, а затем решил сделать первый патч. По привычке я рефлексивно печатал git commit -aвместо простого git commitи нажимал ввод, и, конечно, я потерял все свои патчи, и я получил именно то, что у меня было раньше: один большой коммит.

Есть ли способ вернуться к предыдущей версии моих поэтапных изменений? Я думаю, что хочу вернуться к предыдущей версии моего файла .git / index, однако из того, что я могу сказать, поэтапные изменения не имеют версий. Так что я думаю, что я облажался, и мне просто нужно начать все сначала.

Я использую Git ежедневно в течение нескольких лет, и это случалось несколько раз в прошлом. Каждый раз, когда я понимаю, что я сделал, я сталкиваюсь с лицом и начинаю все сначала. Я подозреваю, что это можно обойти с помощью ловушки перед фиксацией, которая делает копию .git / index (возможно, .git / index.bak), чтобы получить один уровень ручного «отмены», но я не уверен, что это быть достаточным, поскольку у меня нет действительно глубокого понимания внутренних функций Git. Лучшее место, которое я нашел для внутренней информации, это глава 10 книги Git, хотя я подумал о том, чтобы изучить исходный код Git, чтобы лучше понять, как работает промежуточная область.

Заранее спасибо за любые идеи.

Автор: Mike Percy Источник Размещён: 19.09.2019 11:51

Ответы (1)


3 плюса

TL; DR: вы можете использовать git fsck --lost-found

Но это будет больно.

Изменить : если ваша цель состоит в том, чтобы помешать себе делать это в будущем, это немного сложно. Вы можете где-нибудь сохранить исходный (до фиксации) индексный файл; этот индексный файл содержит хэш-идентификаторы объектов BLOB-объектов, содержащих тщательно подготовленные файлы, перед тем, --allкак их перезаписать. Однако найти путь к этому файлу индекса сложно: ваш хук перед фиксацией вызывается с GIT_INDEX_FILEустановкой пути к (теперь заблокированному) «реальному» индексу, содержащему обновленные хэши, а не к индексу сохраненных для отката. Вы можете использовать ужасный хак, который, вероятно, просто .git/index, но это неправильно при наличии добавленных рабочих деревьев (см. git-worktree). Смотрите также buildin / commit.c возле строки 400 .

Более безопасным трюком может быть написание собственного сценария или псевдонима git (см., Например, этот ответ ). Если команда , которую вы бежите это git commitи один из аргументов -a, проверьте ли индекс спичек HEAD(использование git diff-index --cached, см require_clean_work_treeв git-sh-setup.shслучае , если нет, то вы можете требовать какой - то «я действительно имею в виду это» вариант..

Длинное описание

К сожалению, при использовании --allили --includeс указанием путей Git просто перезаписывает существующее содержимое индекса дополнительными или всеми файлами. (Хорошо, если фиксация завершится неудачно , Git восстановит старый индекс, но, по-видимому, фиксация не --onlyудалась .) При использовании с pathspecs ситуация более сложная, но здесь это не так.

Это означает, что интерактивно исправленные версии файлов были потеряны.

С другой стороны, потерянный здесь означает потерянный , а не уничтоженный: они все еще находятся в вашем хранилище, их просто нет простого способа найти . Объекты обычно остаются в хранилище в течение по крайней мере 14 дней после того, как они были впервые написаны, чтобы дать различным частям Git достаточно времени, чтобы прикрепить к ним имена, по которым их можно найти. (Без этого льготного периода любая случайная фоновая операция, которая вызвала автомат, git gcможет уничтожить объекты, над которыми все еще работает какой-то другой процесс Git.)

Что это означает, что вы можете запустить:

git fsck --lost-found

и Git будет медленно и мучительно проходить каждый объект в хранилище, а не только те, которые легко найти, чтобы выяснить , является ли объект может быть найден. Если у объекта есть нормальный способ его найти - например, в коммите - тогда ничего особенного не происходит. Если у объекта нет такого пути , чтобы найти его, Git называет это оборванный объектом (точнее, оборванными блоба или оборванным совершить -ТЫ технический штуковина здесь фиксации , что является особенным, что не относится к сгусткам).

Слово blob здесь по сути означает файл . С помощью --lost-foundэтих «висячих больших двоичных объектов» они копируются в свое расширенное оригинальное текстовое представление файла и вставляются в него .git/lost-found/other/. Основная проблема здесь заключается в том, что имя файла действительно уничтожено (оно было только в индексе), поэтому все эти файлы теперь называются по своим хэш-идентификаторам.

Вероятно, здесь будет много, много версий каждого файла. Вам придется изучить их все и выяснить, что 9ab30ad...это немного неправильно 57e4eea..., но, упс, посмотрите на это, e83c1d7немного лучше, чем любой из них, и ... ну, вы поняли. :-)

Если по какой-то причине версия файла, fooкоторый был исправлен, точно совпадает с любой версией любого файла в любом коммите - например, возможно, правильная версия x.docбыла пустой , и у вас также есть другой пустой файл, который был зафиксирован - тогда не будет висячим блобом для этого файла, потому что существует только одна копия какой-либо конкретной версии данных. (Например, пустой файл имеет идентификатор хеша e69de29bb2d1d6434b8b29ae775ad8c2e48c5391. Каждый пустой файл имеет такой же хэш! Файл hello\nимеет хэш ce013625030ba8dba906f756967f9e9ca394464a. Чтобы увидеть это, запустите echo hello | git hash-object -t blob --stdin.)

Автор: torek Размещён: 21.05.2017 03:34
Вопросы из категории :
32x32