Знаете ли вы, что мы можем использовать справочные журналы Git для восстановления истории коммитов Git(?) Часто мы, разработчики, сталкиваемся с проблемами при работе с Git. Мы можем случайно принудительно отправить коммиты в удаленную основную ветку, выполнить неудачную перебазировку, удалить ветку, которую мы хотели сохранить, или сделать полный сброс до неправильного коммита.

В этом посте мы рассмотрим git reflog а также git reset. Мы рассмотрим некоторые распространенные сценарии восстановления локальных коммитов, восстановления удаленной ветки и отмены принудительных изменений из-за перебазирования.


git рефлог

git рефлог это инструмент, который может помочь нам восстановить практически все — по крайней мере, все, что мы совершили. Инструмент отслеживает коммиты, которые были созданы, а также отброшены в журнале, который называется эталонным журналом. Журнал ссылок хранится на нашем локальном компьютере под .git каталог в локальном репозитории. Он содержит список коммитов, которые HEAD указал и отслеживает всю историю фиксации. Помимо справочного журнала для веток, у нас есть отдельный справочный журнал для тайника.

(Записи истории в ветке по умолчанию истекают через 30 дней. Мы можем изменить дни истечения, запустив git reflog —expire в нашем терминале, если мы хотим сохранить историю в течение более длительного времени.)

Важно знать, что справочные журналы не отслеживать в удаленном репозитории, например, пуш-выборки и клоны; это чисто локально и актуально для рабочей среды. Ниже приведены два снимка экрана: первый из Github Codespaces, а второй из локальной файловой системы, которая изначально создала все коммиты основной ветки в такой же репозиторий:

Кодовые пространства GitHub:
Журнал ссылок из рабочей области в Github Codespaces

Локальный компьютер:
Журнал ссылок с локального компьютера, на котором изначально были созданы коммиты.


Журнал Git против reflog

журнал git это команда, которая показывает список коммитов, связанных с веткой. git reflog похоже на git log но показывает список моментальных снимков и время, когда HEAD был изменен. справочные журналы также ссылаются на другие типы, такие как тайник, ветви, лиса, сливаться а также теги. Ссылка известна как судьии синтаксис для доступа к ним: name@{qualifier}. Бег git reflog это самый простой вариант использования и, по сути, эквивалент записи git reflog show HEAD. Вывод будет выглядеть следующим образом:

=> git reflog

47efaa2 HEAD@{0}: commit: refactor: remove post schema
f243f12 HEAD@{1}: commit: refactor: change author fields
4783ba0 HEAD@{2}: commit: chore: add .env to gitignore
a19d142 HEAD@{3}: commit: chore: update readme
f5ade9a HEAD@{4}: commit: chore: update yarn.lock
854c08f HEAD@{5}: commit (initial): feat: bootstrap sanity studio
Войти в полноэкранный режим

Выйти из полноэкранного режима


Git сбросить

git сброс это команда, которую мы можем использовать, чтобы вернуться к предыдущему коммиту, отменив или отменив предыдущие изменения. мы можем бежать git reset --hard <commit_sha> чтобы переместить нашу ветку обратно в историю коммитов.

Жесткий сброс (git reset --hard) будут полностью уничтожить любые изменения и удалите их из локального репозитория.

Мягкий сброс (git reset --soft) сохранит ваши изменения и автоматически вернет их обратно.

Смешанный сброс (git reset --mixed), который используется по умолчанию, сохранит ваши изменения, но они также станут неустановленными. Несмотря на то, что он гибкий, вам придется вносить изменения вручную.


Восстановить локальные коммиты


Сценарий

Мы сделали несколько коммитов, которые еще не были отправлены в удаленный репозиторий. Мы делаем git reset —-hard <commit_sha> к предыдущему коммиту, а наша локальная ветвь возвращается к более ранней точке и отбрасывает всю историю после выбранного коммита. Затем мы запускаем git log и увидеть, что коммиты исчезли. Мы не можем получить изменения из удаленного репозитория, так как мы никогда не синхронизировали изменения.


Как восстановить локальные коммиты

При запуске git reflog мы видим, что наши изменения по-прежнему отслеживаются журналом ссылок; у нас даже есть отдельный коммит для жесткого сброса, который мы сделали ранее — взгляните на коммит f243f12 на HEAD@{0}:

f243f12 HEAD@{0}: reset: moving to f243f12
eec6f27 HEAD@{1}: commit: refactor: author should not have image
47efaa2 HEAD@{2}: commit: refactor: remove post schema
f243f12 HEAD@{3}: commit: refactor: change author fields
Войти в полноэкранный режим

Выйти из полноэкранного режима

С помощью этой информации мы можем сбросить нашу ветку обратно в состояние, которое мы отбросили, используя одну из ссылок в журнале ссылок. Мы можем переместить нашу ветку в выбранный коммит, запустив git reset --hard <commit_sha>:

=> git reset --hard f243f12
=> git reflog

f243f12 HEAD@{0}: reset: moving to eec6f27
f243f12 HEAD@{1}: reset: moving to f243f12
eec6f27 HEAD@{2}: commit: refactor: author should not have image
47efaa2 HEAD@{3}: commit: refactor: remove post schema
f243f12 HEAD@{4}: commit: refactor: change author fields
Войти в полноэкранный режим

Выйти из полноэкранного режима


Восстановить удаленную ветку

Мы можем восстановить удаленные ветки, используя SHA в справочных журналах.


Сценарий

Нередко мы можем проверить новую ветку в нашей локальной среде. Мы могли бы иметь ветку под названием chore/update-packages и зафиксируйте изменение, которое добавляет дайджес как пакет:

=> git checkout -b chore/add-dayjs-package
=> yarn add dayjs
=> git add .
=> git commit -m 'chore: add dayjs package'

5a75042 HEAD@{0}: commit: chore: add dayjs package
Войти в полноэкранный режим

Выйти из полноэкранного режима

Позже мы проверяем главный ветвь и удаляет chore/add-dayjs-package ветка — возможно, она нам больше не понадобилась по каким-то причинам:

=> git checkout main

47efaa2 HEAD@{0}: moving from chore/add-dayjs-package to main

=> git branch -D chore/add-dayjs-package

Deleted branch chore/add-dayjs-package (was 5a75042)
Войти в полноэкранный режим

Выйти из полноэкранного режима

Мы получим подтверждающее сообщение о том, что git удалил ветку. Через некоторое время мы обнаруживаем, что нам все-таки могут понадобиться изменения, так как же нам вернуть их обратно?


Как восстановить удаленную ветку

Мы можем отменить эти изменения с помощью git reflog а также git checkout. Если мы побежим git reflog мы не увидим никаких ссылок на удаленную ветку. Мы могли бы использовать SHA фиксации, указанный в сообщении об удалении (5a75042), чтобы отменить последнюю фиксацию в этой ветке. Но если мы потеряли сообщение, нам нужно использовать справочный журнал. И если вы правильно назвали свои коммиты, должно быть легко найти отсутствующий коммит, взгляните на коммит 5a75042 на HEAD@{1}:

=> git reflog

// deletion of a branch is not logged to the reference log
47efaa2 HEAD@{0}: moving from chore/add-dayjs-package to main
5a75042 HEAD@{1}: commit: chore: add dayjs package
47efaa2 HEAD@{2}: moving from main to chore/add-dayjs-package
Войти в полноэкранный режим

Выйти из полноэкранного режима

Теперь мы можем проверить удаленный коммит SHA и создать новую ветку из этого коммита. git checkout -b <branch_name>:

=> git checkout 5a75042
=> git checkout -b chore/add-dayjs-package
Войти в полноэкранный режим

Выйти из полноэкранного режима


Отменить принудительно внесенные изменения


Сценарий

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

=> git reset --hard <commit_sha>
=> git push --force
Войти в полноэкранный режим

Выйти из полноэкранного режима


Как отменить принудительные изменения

Мы можем использовать git reflog и git reset для восстановления принудительных изменений:

=> git reflog

f243f12 HEAD@{0}: reset: a19d142 to f243f12
Войти в полноэкранный режим

Выйти из полноэкранного режима

Читая журнал, мы видим, что сообщение о HEAD@{0} является reset: a19d142 to f243f12что означает, что коммит с хешем a19d142 был насильно подтолкнут f243f12. Это также дает нам информацию о том, какой коммит нам нужно восстановить, тот с хэшем a19d142. Мы можем просто выполнить ту же процедуру, что и изначально, чтобы вернуться к переопределенной фиксации:

git reset --hard a19d142
git push --force
Войти в полноэкранный режим

Выйти из полноэкранного режима

Наконец, мы принудительно отправляем новые изменения в удаленный репозиторий. Всегда будьте осторожны и проверяйте, что вы находитесь на правильной ветке, прежде чем выполнять принудительное нажатие. Особенно для того, чтобы предотвратить изменение производственного кода или перезапись кода члена команды.

Спасибо за чтение! (Эта статья была изначально опубликовано на Medium )

Код для шиззла