git fsck: duplicateEntries: содержит повторяющиеся записи в файле - не может перейти на gitlab - PullRequest
7 голосов
/ 28 мая 2019

У нас есть большой репозиторий git, который я хочу перенести в автономный экземпляр gitlab.

Проблема в том, что пульт gitlab не позволяет мне выдвигать репозиторий:

git push --mirror https://mygitlab/xy/myrepo.git

Это даст мне эту ошибку:

Enumerating objects: 1383567, done.
Counting objects: 100% (1383567/1383567), done.
Delta compression using up to 8 threads
Compressing objects: 100% (207614/207614), done.
remote: error: object c05ac7f76dcd3e8fb3b7faf7aab9b7a855647867: 
duplicateEntries: contains duplicate file entries
remote: fatal: fsck error in packed object    

Итак, я сделал git fsck:

error in tree c05ac7f76dcd3e8fb3b7faf7aab9b7a855647867: duplicateEntries: contains duplicate file entries
error in tree 0d7286cedf43c65e1ce9f69b74baaf0ca2b73e2b: duplicateEntries: contains duplicate file entries
error in tree 7f14e6474400417d11dfd5eba89b8370c67aad3a: duplicateEntries: contains duplicate file entries

Затем я проверил git ls-tree c05ac7f76dcd3e8fb3b7faf7aab9b7a855647867:

100644 blob c233c88b192acfc20548d9d9f0c81c48c6a05a66    fileA.cs
100644 blob 5d6096cb75d27780cdf6da8a3b4d357515f004e0    fileB.cs
100644 blob 5d6096cb75d27780cdf6da8a3b4d357515f004e0    fileB.cs
100644 blob d2a4248bcda39c0dc3827b495f7751b7cc06c816    fileC.xaml

Обратите внимание, что fileB.cs отображается дважды с одинаковым хешем.Я предполагаю, что это проблема, потому что почему файл будет два раза в одном и том же дереве с одним и тем же именем файла и хэшем BLOB-объектов?

Теперь я погуглил проблему, но не смог найти способ, как это исправить.,Один, казалось бы, хороший ресурс, который я нашел, был таким: Дерево содержит повторяющиеся записи в файлах

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

Тогда есть этот, который, кажется, удаляет файл полностью (но мне все еще нужен файл, но только один раз, а не два раза в дереве): https://stackoverflow.com/a/44672692/826244

Есть ли другой способ исправить это?Я имею в виду, что действительно нужно исправить, чтобы git fsck не выдавал ошибок, верно?Я знаю, что мне нужно будет переписать всю историю после испорченных коммитов.Я даже не мог найти способ получить коммит, который указывает на конкретные деревья, иначе я мог бы использовать перебазирование и исправление поврежденного коммита или чего-то еще.Любая помощь будет принята с благодарностью!

ОБНОВЛЕНИЕ: Я уверен, что я знаю , что делать, но пока не , как сделать:

  1. Создание нового объекта дерева из старого дерева, но с исправлением с помощью git mktree <- done </li>
  2. Создание нового коммита, идентичного старому, который ссылается на плохое дерево, но с новым фиксированным деревом <- сложно, я не могу легко получить коммит в дерево, моё текущее решение запускается как час или больше, и я не знаю, как создать модифицированный коммит, как только я его найду </li>
  3. Выполнить git filter-branch -- --all<- Должны сохраняться замены коммитов </li>

К сожалению, я не могу просто использовать git replace --edit на плохом дереве и затем запустить git filter-branch -- --all, потому что filter-branch, кажется, работает только на коммитах, но игнорирует дерево-replaces ...

Ответы [ 4 ]

1 голос
/ 18 июня 2019

Окончательное решение было написать инструмент, который решает эту проблему.

Первым шагом было git unpack-objects для всех packfiles. Затем я должен был идентифицировать коммиты, которые указывали на записи дерева с дубликатами, читая все ссылки и затем возвращаясь к истории, проверяя все деревья. После того, как у меня были инструменты для этого, было не так сложно переписать деревья этих коммитов, а затем переписать все коммиты после этого. После этого мне пришлось обновить измененные ссылки. Это момент, когда я тщательно проверил результат, так как ничего еще не было потеряно. Наконец git reflog expire --expire=now --all && git gc --prune=now --aggressive переписал пакет и удалил все незакрепленные предметы, которые больше не доступны.

Когда у меня будет время, я буду загружать исходный код в github, так как он работает очень хорошо и может быть шаблоном для решения подобных проблем. Он работал всего несколько минут в 3.7 ГБ хранилище (около 20 ГБ в распакованном виде). К настоящему времени я также реализовал чтение из файлов пакетов, поэтому больше не нужно ничего распаковывать (что занимает много времени и места).

Обновление: я немного поработал над исходным кодом, и теперь он работает очень хорошо, даже лучше, чем bfg для удаления одного файла (пока нет переключателей). Исходный код доступен здесь: https://github.com/TimHeinrich/GitRewrite Имейте в виду, это было протестировано только для одного репозитория и только под Windows на ядре i7. Маловероятно, что он будет работать на Linux или с любой другой архитектурой процессора

1 голос
/ 07 июня 2019

Вы можете попробовать запустить git fast-export, чтобы экспортировать репозиторий в файл данных, а затем запустить git fast-import, чтобы повторно импортировать файл данных в новый репозиторий.Git удалит все повторяющиеся записи во время процесса быстрого импорта, что решит вашу проблему.

Помните, что вам может потребоваться принять решение о том, как обрабатывать подписанные теги и т. Д., При экспорте с помощью передачи соответствующих аргументов.до git fast-export;поскольку вы переписываете историю, вы, вероятно, хотите передать --signed-tags=strip.

0 голосов
/ 07 июня 2019

Я обнаружил проблему, связанную с отсутствием fsck.skipList в gitlab, и я думаю, что решение может применяться:

Чтобы перейти к новому проекту в gitlab, парень использовал функцию импорта при создании этого GitLab.проект, и он импортировал его прямо из своего другого репозитория.

Примечание: он не фиксировал его локально, но позволял импортировать его и, возможно, импорт таким образом сгенерировал чистую ветку удаленно.

0 голосов
/ 06 июня 2019

Вы можете удалить связанные ссылки и истечь срок их объектов.

Чтобы найти связанные ссылки, выполните:

$ git log --all --format=raw --raw -t --no-abbrev

и найдите изменение sha, затем найдите его в $ git show-refs

Далее для каждого реф, содержащего плохие объекты, выполните:

$ git update-ref -d refs/changes/xx/xxxxxx/x

Наконец, истекайте срок действия объектов и запускайте fsck, это должно быть исправлено.

$ git reflog expire --expire=now --all
$ git gc --prune=now --aggressive
$ git fsck
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...