Как связать две истории мерзавца?

У меня есть два репозитория мерзавца, которые мимоходом связаны. А именно, содержание каждый был предшественником другого. Я хотел бы так или иначе предварительно ожидать полную историю хранилища в хранилище B, так, чтобы подсказка A была родителем самого первого changeset репозитория B? Истории в обоих довольно линейны.

Действительно ли это возможно?

12
задан Qix 13 July 2015 в 20:38
поделиться

1 ответ

Вы можете попробовать использовать файл graft (.git/info/grafts), в котором вы можете переписать отцовство коммита (например, первый из projectB имеет в качестве родителя последний из projectA)

См. также "Что такое . git/info/grafts?" и "Как добавить прошлое в git-репозиторий?" для получения дополнительной информации об этой манипуляции.


skalee комментарии к статье "Git: Grafting repositories" (от пользователя SO Ben Straub) для конкретного примера.

Теперь мы хотим изменить первый коммит в репозитории "nuevo" ("New commit #1") так, чтобы его родителем стал последний коммит в "старом" репозитории ("Old #3"). Время для вуду:

git fetch ../old master:ancient_history

Git позволяет вам получать данные из любого другого git-репозитория, независимо от того, связан этот репозиторий с ним или нет! Блестяще! В результате мы получаем следующее:

enter image description here

Обратите внимание, как мы переименовали старую ветку master в ancient_history. Если бы мы этого не сделали, git попытался бы объединить эти две ветки и, вероятно, сдался бы с отвращением.

Теперь у нас всё ещё есть проблема.
Эти два дерева не связаны, и на самом деле git pull даже не получит ветку ancient_history. Нам нужен способ установить связь между ними.

В Git есть средство под названием graft, которое, по сути, подделывает родительскую связь между двумя коммитами.
Чтобы создать такую связь, просто вставьте строку в файл .git/info/grafts в таком формате:

[ref] [parent]

Обе эти строки должны быть полным хэшем рассматриваемых коммитов. Так что давайте найдём их:

$ git rev-list master | tail -n 1
d7737bffdad86dc05bbade271a9c16f8f912d3c6

$ git rev-parse ancient_history
463d0401a3f34bd381c456c6166e514564289ab2

$ echo d7737bffdad86dc05bbade271a9c16f8f912d3c6 \
       463d0401a3f34bd381c456c6166e514564289ab2 \
       > .git/info/grafts

(в одной строке, как предложил ssokolow)

echo $(git rev-list master | tail -n 1) $(git rev-parse ancient_history) > .git/info/grafts 

Вот. Теперь наша история выглядит так:

enter image description here

Клонирование этого репозитория приводит к следующему:

enter image description here

Упс. Оказывается, прививки действуют только для локального репозитория. Мы можем исправить это разумным применением git fast-import:

$ git fast-export --all > ../export

$ mkdir ../nuevo-complete

$ cd ../nuevo-complete

$ git init

$ git fast-import < ../export
git-fast-import statistics: [...]

(в одну строку, как предложил ssokolow)

git filter-branch $(git rev-parse ancient_history)..HEAD 

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

enter image description here

Как Qix комментирует ниже:

fast-import, похоже, просто импортирует информацию git, но ничего не проверяет.
git init изначально помещает вас на master, поэтому вам нужно git reset --hard HEAD, чтобы действительно проверить файлы после fast-import.

11
ответ дан 2 December 2019 в 22:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: