Как объединить две истории git? - PullRequest
12 голосов
/ 10 июля 2010

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

Возможно ли это?

1 Ответ

10 голосов
/ 10 июля 2010

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

См. Также« Для чего нужны .git / info / grafts? » и « Как добавить прошлое в репозиторий git? », чтобы узнать больше об этой манипуляции.


скали комментарии к статье " Git: прививка репозиториев " (от пользователя SO Бен Штрауб )для конкретного примера.

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

git fetch ../old master:ancient_history

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

enter image description here

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

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

В 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

Woops.Оказывается, что прививки вступают в силу только для локального хранилища.Мы можем исправить это с помощью разумного применения 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

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

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

...