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

259

Сначала получил «ваша ветка опережает источник / мастер на 3 коммита», затем мое приложение вернулось к более раннему времени с более ранними изменениями.

Как я могу получить то, что я потратил за последние 11 часов?

Elias7
источник

Ответы:

589

git reflogтвой друг. Найдите коммит, который вы хотите включить в этот список, и вы можете сбросить его (например:git reset --hard e870e41 .

(Если вы не зафиксировали свои изменения ... у вас могут быть проблемы - делайте это рано и часто!)

янтарный
источник
5
Посмотрите на git log HEAD@{1}. Если это выглядит как правильная серия коммитов, то вы можете git reset HEAD@{1}.
Январь
4
Только если коды размещены (используя git add), они хранятся в git и могут быть легко найдены с помощью таких команд, как git fsck --lost-found.
Landys
2
Случайно уронил коммит, который я должен был оставить при перебазировании. Это полностью спасло меня от повторной работы за пару часов.
19
27
Это спасло мою жизнь.
Лутаая Хузаифа Идрис
6
Это спасло мое здравомыслие: D
Фрэнк Фахардо
120

Прежде чем ответить, давайте добавим некоторый фон, объясняя, что это HEADтакое.

First of all what is HEAD?

HEADэто просто ссылка на текущий коммит (последний) в текущей ветке.
В HEADлюбой момент времени может быть только один (исключая git worktree).

Содержимое HEADхранится внутри .git/HEADи содержит 40 байтов SHA-1 текущего коммита.


detached HEAD

Если вы не используете последний коммит, то HEADесть он указывает на предыдущий коммит в истории detached HEAD.

Введите описание изображения здесь

В командной строке это будет выглядеть так - SHA-1 вместо имени ветви, так как HEADне указывает на конец текущей ветви:

Введите описание изображения здесь

Введите описание изображения здесь


Несколько вариантов того, как восстановить систему с отключенной HEAD:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

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

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

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

Каждый раз, когда ГОЛОВКА модифицируется, в reflog

git reflog
git checkout HEAD@{...}

Это вернет вас к желаемой фиксации

Введите описание изображения здесь


git reset --hard <commit_id>

«Переместите» ГОЛОВУ назад к желаемому коммиту.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Примечание: ( начиная с Git 2.7 ) вы также можете использовать git rebase --no-autostash.

git revert <sha-1>

"Отменить" данный диапазон фиксации или фиксации.
Команда сброса «отменит» любые изменения, сделанные в данном коммите.
Новый коммит с патчем отмены будет зафиксирован, в то время как оригинальный коммит останется в истории.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Эта схема иллюстрирует, какая команда что делает.
Как вы можете видеть, reset && checkoutизмените HEAD.

Введите описание изображения здесь

CodeWizard
источник
2
Вы герой, сэр
dylanh724
4
Это просто сэкономило мне много часов работы. Я использовал "git reflog --date = iso", чтобы увидеть дату / время для каждой записи, так как я не мог сказать точно без временной отметки.
MetalMikester
1
для меня, во git reset --hard <commit_id>, удаление HEADработало! +1 для графического представления !!
reverie_ss
Просто упомянуть: если вы знаете название ветви: это git reflog <branchname>может быть весьма полезно, так как вы видите изменения только одной ветви.
Маркус Шрайбер
35

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

git fsck --lost-found

Это выведет что-то вроде последней строки:

dangling commit xyz

Мы можем проверить, что это тот же коммит, который используется reflogв других ответах. Теперь мы можем сделатьgit merge

git merge xyz

Примечание.
Мы не сможем вернуть коммит, fsckесли уже выполнили git gcкоманду, которая удалит ссылку на висячий коммит.

Атри
источник
3
Это единственный ответ, который работает, если вы недавно не указали на коммит, например, когда вы выбираете ветку, а затем случайно сбрасываете эту ветку в другом месте.
TamaMcGlinn