10.7. Maintenance and Data Recovery

Это типа конспект, который я веду для себя, чтобы получше разобраться и запомнить. Вероятно, вам лучше сразу читать оригинал: 10.7 Maintenance and Data Recovery.

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

Maintenance and Data Recovery

Maintenance

Время от времени Git вызывает «auto gc», который чаще всего ничего не делает, но при некоторых условиях может вызвать полноценный git gc.

«Auto-gc» запускается командой git gc --auto. Эта команда скорее всего ничего не будет делать. Нужно иметь более 7000 потерянных объектов или 50 пак-файлов, чтобы запустился нормальный GC. Эти пределы настраиваются в настройках gc.auto и gc.autopacklimit.

Помимо прочего GC пакует ветки и тэги в файл.git/packed-refs, удаляя их с обычного места. Если ветка обновляется, то гит пишет её новую ссылку на обычное место. Если вы не видите свою ветку на обычном месте, то может быть она запакована в packed-refs и с тех пор не обновлялась.

Эээксперимент про «auto-gc» (провалился)

С полпинка мне не удалось заставить вызвать настоящий GC через «auto-gc» на мелком свежесозданном репозитории на два коммита и один файл.

Эээксперимент про «packed-refs»

Имеем мелкий репозиторий:

В нём какие-то рефы:

Делаем GC, рефы исчезли, но зато появился packed-refs:

Делаем коммит в мастер, смотрим, что произошло с рефами:

Видим, что снова появился файл с рефом, а packed-refs не изменились.

Data Recovery

В этом разделе рассматривается пример, когда вы грохнули ветку или хард-ресетнули и хотите восстановить доступ к пропавшим коммитам, хотя не помните их айдишники.

Reflog

Чаще всего вас спасёт команда git reflog или git log -g, она покажет все перестановки ссылки HEAD с места на место. В том числе поэтому при изменении веток стоит использовать команду git update-ref вместо прямой записи в файл ветки.

У меня такой лог:

Делаем ресет на первый коммит:

git log -g тоже что-то весёленькое показывает.

Так мы видим коммит 2806732 и можем ресетнуться обратно.

Fsck

Если же рефлог тоже пропал или коммита там не найти, то можно попытать команду git fsck --full, которая анализирует целостность и показывает недостижимые объекты.

Грохаем reflog, теперь он ничего не показывает, просто гит-лог работает:

Пробуем fsck:

Нашёл. Пока мы не грохнули reflog, он ничего не показывал. Финальный шаг:

Removing Objects

Тут рассматривают технику удаления больших файлов. Добавим и удалим большой файл и ещё чего-нибудь накоммитим. Итак, имеем следующую картину:

Сделаем gc и count-objects:

size-pack в килобайтах, значит у нас 2М где-то завалялось.

Такая команда позволяет найти большие объекты:

Ищем, что это за файл:

Так мы ищем в каких коммитах этот файл менялся:

Так мы выпиливаем его из коммитов, я сейчас ничерта не понимаю, почему это работает, подробности должны быть в Rewriting History):

Он переписал историю, коммиты теперь другие:

Исходную ветку он спрятал под refs/original и reflog всё помнит:

Репозиторий всё ещё гигант:

Грохаем старую ветку и логи:

Размер переместился из пака в объекты:

Я грохнул объект командой git prune, хотя в книжке пишут, что нужна команда git prune --expire now. Значения по умолчанию для --expire я с полпинка не нашёл.