Мерзкие заметки после BFG?

Я мигрировал из SVN в git, и в каждом коммите git была заметка, ссылающаяся на номер ревизии SVN. После импорта репо я использовал BFG очиститель репо, чтобы очистить историю Git от бинарных файлов и другого мусора. К сожалению, теперь я не вижу заметки, когда я печатаю git log, Я предполагаю, что BFG забудет обновить ссылки на коммиты для заметок. BFG оставляет отчет *.txt с отображением старого идентификатора объекта в новый идентификатор объекта в следующем формате:

0001b24011381e8885683cd1119ba4cb077fa64b c81149b1b52b9e1e1767d6141f292891d715edb5
00024eecdc31f2f6e67018f7d6f00e7c1ad03f1f 326ee3b508e3dd2934ec1f50069195f86ea1a1c7
00028e04dcc2d59bd835b447bd3a207ae481696c 3d18e9b9d3336e59d62093200b81603ffefcc747

Можете ли вы предложить какой-нибудь скрипт для быстрого исправления заметок с учетом приведенного выше сопоставления?

PS: я почти уверен, что проблема вызвана не обновленными ссылками, потому что, когда я печатаю git notes во-вторых, я могу видеть ссылки, которые считаются старыми в BFG repot object-id-map.old-new.txt

2 ответа

Решение

Я написал следующий скрипт для переноса моих заметок со старых объектов. Решение медленное в одном потоке, не уверен, безопасно ли запускать несколько git notes команды параллельно.

while read string; do
    hashesArray=($string)
    git notes copy ${hashesArray[0]} ${hashesArray[1]}
    git notes remove --ignore-missing ${hashesArray[0]}
done <object-id-map.old-new.txt

Там нет ничего встроенного, чтобы сделать это; вам придется написать сценарий или программу самостоятельно. С другой стороны, BFG оставил вам файл карты: это намного лучше, чем git filter-branch, который выбрасывает его, так что информация, необходимая для обновления ваших заметок, исчезла.

Основная реализация заметок заключается в том, что refs/notes/commits (или что бы вы ни выбрали core.notesRef) указывает на обычный коммит, который можно хотя бы теоретически git checkout (вероятно, во временное рабочее дерево, которое вы создали специально для этой цели). Это дерево содержит файлы, имена которых являются аннотированными коммитами - только слегка измененные. Например, если:

0001b24011381e8885683cd1119ba4cb077fa64b c81149b1b52b9e1e1767d6141f292891d715edb5

является отображением записи, с 0001b24011381e8885683cd1119ba4cb077fa64b будучи старым коммитом, и если 0001b24011381e8885683cd1119ba4cb077fa64b есть запись заметок, там будет файл, имя которого 0001b24011381e8885683cd1119ba4cb077fa64b- только это может быть 00/01b2... или же 00/01/b2...,

Глубина вложения всех этих добавленных подкаталогов динамически управляется кодом заметок, при этом основная идея заключается в том, чтобы "добавить столько деревьев, сколько необходимо, чтобы быстро находить, есть ли заметка, но не так много деревьев, чтобы занять много". пространства в хранилище, когда очень мало заметок, начинающихся с 0001b2..., Это разветвление не имеет решающего значения для ваших целей, хотя вы, возможно, захотите сохранить его по тем же причинам скорости.

Ваша задача - найти каждый файл в этом дереве под его старым именем и переместить (или скопировать) его в новое имя, соответствующее новому идентификатору фиксации. Поскольку новое имя в этом случае будет c81149b1b52b9e1e1767d6141f292891d715edb5, вы бы переименовали файл как c8/1149b1b52b9e1e1767d6141f292891d715edb5, или же c8/11/49b1b52b9e1e1767d6141f292891d715edb5и т. д. После того, как вы переименовали все файлы (через индекс: используйте git mv или же git rm --cached а также git add по мере необходимости), вы можете превратить их в обычный объект коммита git write-tree с последующим git commit-tree, Сделайте родителя нового коммита существующим refs/notes/commits совершать и использовать git update-ref обновлять refs/notes/commits чтобы указать на новый коммит, и ваши заметки должны появиться снова, после фильтрации.

(Если у вас есть такая вещь, было бы неплохо присоединиться к ней git filter-branch и / или сама BFG.)

Другие вопросы по тегам