Как распаковать упакованные вещи? - PullRequest
16 голосов
/ 26 июля 2010

Я клонировал проект из github с git clone --mirror .В результате у меня остался репозиторий с файлом pack-refs , файлом .pack и файлом .idx .В целях разработки я хочу посмотреть на незакрепленные объекты, поэтому я распаковал объекты с помощью git unpack-objects <</em>, который работал нормально (я распаковал упаковочный файл в новый репозиторий, если вам интересно).Единственное, что refs / возглавляет / все еще пусто, все ссылки все еще только в pack-refs , но они мне нужны в refs /heads / Мне не удалось найти команду, которая бы извлекала или распаковывала эти ссылки, и я почему-то не могу поверить, что мне придется делать это вручную (или с помощью каналов).

Так что на самом деле у меня есть два вопроса:

  1. Есть ли простой способ "восстановить" ссылки из pack-refs ?
  2. Если нет, то почему бы и нет?Если есть команда для распаковки объектов, почему вы не предоставляете то же самое для ссылок (не забывайте, что есть даже команда git pack-refs ...)

Спасибо за любые советы и идеи.

Ответы [ 4 ]

29 голосов
/ 26 июля 2010

Короткий ответ - «нет» - «простого способа» распаковать ссылки не существует так, как вы просите.

Немного более длинный ответ: каждая ссылка - это всего лишь 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', которое вы можете использовать для расширения своих собственных псевдонимов.

13 голосов
/ 27 июля 2010

Причина, по которой существуют упакованные ссылки, заключается в том, чтобы ускорить доступ в репо с миллионами ссылок - проще посмотреть на один файл с несколькими строками, чем попасть в файловую систему один раз для каждой ссылки.Все, что нужно знать о refs в git, проходит через код, который может читать как каталог refs, так и упакованный файл refs.Распаковка его уничтожит его цель.Если вы хотите получить доступ к ссылкам, используйте сантехнические команды (например, show-ref, for-each-ref, update-ref ...).Я не могу придумать какой-либо вид доступа, который был бы быстрее и проще с структурой каталогов, чем с сантехническими командами (особенно с доступным для каждого ссылки).

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

Однако, когда пакетпереносится с пульта, распаковывается с локальной стороны.Я вижу вызов метода unpack в источнике git receive-pack, а на справочной странице pack-objects написано:

Команда git unpack-objects может прочитать упакованный архив и развернуть объекты, содержащиеся вупаковать в формате «один файл - один объект»;Обычно это делается командами smart-pull, когда пакет создается «на лету» для эффективной передачи по сети их партнерами.

2 голосов
/ 23 января 2017

Еще один ответ на ваш вопрос 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 / pack-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) упакованные ссылки удаляются из файла .git / pack-refs и

Б) файлы .git / info / refs и .git / objects / info / packs удалены.

Я признаю, что удаление файлов в папке .git может быть не очень хорошей идеей, однако это то, что мне нужно было сделать для чистой распаковки.

На вопрос 2 все еще не дан ответ.

0 голосов
/ 09 апреля 2018

Есть обходной путь, который сработал для меня и может сработать для некоторых из вас:

В основном, удалите все теги локально (удаляет его из упакованных ссылок) и затем извлеките его снова.

git tag | xargs git tag -d && git fetch --tags
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...