У меня есть два репозитория мерзавца, которые мимоходом связаны. А именно, содержание каждый был предшественником другого. Я хотел бы так или иначе предварительно ожидать полную историю хранилища в хранилище B, так, чтобы подсказка A была родителем самого первого changeset репозитория B? Истории в обоих довольно линейны.
Действительно ли это возможно?
Вы можете попробовать использовать файл 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-репозитория, независимо от того, связан этот репозиторий с ним или нет! Блестяще! В результате мы получаем следующее:
Обратите внимание, как мы переименовали старую ветку 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
Вот. Теперь наша история выглядит так:
Клонирование этого репозитория приводит к следующему:
Упс. Оказывается, прививки действуют только для локального репозитория. Мы можем исправить это разумным применением
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
Это эффективно преобразует нашу "фальшивую" ссылку на историю в настоящую.
Всем инженерам придётся заново клонировать из этого нового хранилища, поскольку хэши будут разными, но это небольшая цена за отсутствие простоев и полную историю.
fast-import
, похоже, просто импортирует информацию git, но ничего не проверяет.
git init
изначально помещает вас на master, поэтому вам нужноgit reset --hard HEAD
, чтобы действительно проверить файлы послеfast-import
.