Как объединить две истории git?

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

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

Ответы

Ответ 1

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

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


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

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

git fetch ../old master:ancient_history

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

enter image description here

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

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

Git имеет объект, называемый трансплантатом, который в основном подделывает родительскую связь между двумя коммитами.
Чтобы сделать это, просто вставьте строку в файл .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

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

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