Как распаковать упакованные ссылки?
Я клонировал проект из github с git clone --mirror. Это оставило меня с репозиторием с файлом упакованных refs, файлом .pack и .idx. В целях развития я хочу посмотреть на свободные объекты, поэтому я распаковал объекты с помощью git unpack-objects < < пакетный файл > который отлично работал (я распаковал пакетный файл в новое репо, если вам интересно). Дело только в том, что refs/heads/все еще пуст, все refs все еще только в упакованных ref, но мне нужны они в refs/heads/.
Мне не удалось найти команду, которая будет извлекать или распаковывать эти ссылки, и я могу как-то не поверить, что мне придется делать это вручную (или через каналы).
Итак, у меня есть два вопроса:
- Есть ли простой способ "восстановить" refs из упакованных ссылок?
- Если нет, почему этого не происходит? Если есть команда для распаковки объектов, в чем причина отсутствия того, чтобы не предоставлять то же самое для ref (не забывайте, что там даже команда git pack-refs...)
Спасибо за любые советы и идеи.
Ответы
Ответ 1
Короткий ответ - "нет" - нет "простого способа" для распаковки ссылок, как вы просите.
Несколько более длинный ответ: каждый ref является всего лишь 41-байтовым текстовым файлом (40 байт SHA1 в шестнадцатеричной + новой строке) в определенном пути, поэтому для "жесткой" версии просто требуется что-то вроде этого в вашем ~/.gitconfig
:
[alias]
unpack-refs = "!bash -c 'IFS=$''\\n''; for f in $(git show-ref --heads); do /bin/echo ''Writing '' $(echo $f | cut -c42-); echo $(echo $f | cut -c1-40) > \"${GIT_DIR:-.git}/$(echo $f | cut -c42-)\"; done'"
Взял немного хитрости, чтобы понять, как заставить его работать правильно, но вот и все! Теперь у вас есть git unpack-refs ', и он делает то, что вы ожидаете, и в качестве бонуса он даже работает с $GIT_DIR, если этот набор (в противном случае он предполагает, что вы находитесь в корне дерева git). Если вы не прочитали псевдонимы git, https://git.wiki.kernel.org/index.php/Aliases - отличная ссылка и даже включает пример 'git alias' расширение, которое вы можете использовать для расширения собственных псевдонимов.
Ответ 2
Причина, по которой упакованные refs существуют, - ускорить доступ в репо с помощью zillions refs - проще просмотреть один файл со многими строками, чем разбить файловую систему один раз для каждого отдельного ref. Все, что содержится в git, которое должно знать о ссылках, проходит через код, который может читать как каталог refs, так и упакованный файл refs. Распаковка это победит его цель. Если вы хотите получить доступ к refs, используйте команды сантехники (например, show-ref, for-each-ref, update-ref...). Я не могу думать о каком-либо доступе, который будет быстрее и проще с структурой каталогов, чем с помощью команд сантехники (особенно для каждого доступного).
И да, упакованные объекты (например, упакованные ссылки) созданы для повышения производительности, но там огромная разница. Упакованный файл refs - это всего лишь куча независимых строк. Вы можете, по сути, бесплатно, добавить или удалить из него. Там нет необходимости распаковывать его, чтобы изменить его. С другой стороны, упакованные объекты дельта-сжаты, поэтому объекты внутри зависят друг от друга. Они значительно сокращают использование диска, и объекты могут быть прочитаны из них по разумной цене, но попытка изменить набор объектов в пакете намного дороже, чем изменение свободных объектов, поэтому он периодически выполняется только с помощью git repack
(называемый git gc
), хотя я не верю, что git repack
фактически распаковывает объекты - он просто считывает их из пакета, упаковывает их в свободные и создает новый пакет.
Однако, когда пакет передается с пульта, он распаковывается с локальной стороны. Я вижу вызов метода распаковки в источнике git receive-pack
, а в man-странице pack-objects
говорится:
Команда git unpack-objects может считывать упакованный архив и разворачивать объекты, содержащиеся в пакете, в формат "один файл одного объекта"; это обычно делается командами smart-pull, когда пакет создается "на лету" для эффективного сетевого транспорта своими сверстниками.
Ответ 3
Еще один ответ на ваш вопрос 1:
Я предполагаю, что вы уже использовали такой цикл, чтобы использовать git unpack-objects:
mkdir CLONE
mv .git/objects/pack/* CLONE/
for pack in CLONE/*.pack; do
git unpack-objects < $pack
done
rm -rf CLONE/
который распаковывает все объекты, но оставляет заголовки упакованных ветвей в файле .git/packed-refs
Благодаря ответу Кле, который я использовал повторно, я обнаружил, что для распаковки ветвей ветвей потребуются следующие команды и очистка:
(
IFS=$'\n'; # set the input field separator to new line
for f in $(git show-ref --heads); do
ref_hash="$(echo $f | cut -c1-40)"
ref_label="$(echo $f | cut -c42-)"
echo " unpack: $ref_hash $ref_label"
echo "$ref_hash" > ".git/$ref_label";
sed -i "s~^${ref_hash} ${ref_label}\$~~" .git/packed-refs
sed -i '/^$/d' .git/packed-refs
done
rm .git/info/refs
rm .git/objects/info/packs
)
Обратите внимание на разницу с ответом Кли:
A) упакованные refs удаляются из файла .git/упакованный refs и
B) удаляются файлы .git/info/refs и .git/objects/info/pack.
Я признаю, что было бы неплохо удалять файлы так же, как в папке .git, но это то, что мне нужно было сделать, чтобы сделать чистую распаковку.
Вопрос 2 все еще не ответил.