Объедините два репозитория Git и сохраните историю

Я хочу продолжить еще один вопрос: Объединить два репозитория Git и сохранить главную историю

Мне удалось слить 2 разных репо в одно репо. Для этого мне понадобилась перезагрузка. Мастер прав, но Я также хочу сохранить историю слияния. Возможно ли это?

У меня есть 2 репозитория:

Repo A

Repo B

Это результат после перезагрузки. Время верхнего репо - это время восстановления. Исходная дата потеряна!

Rebase

Вот как я это сделал:

# Assume the current directory is where we want the new repository to be created
# Create the new repository
git init

# Before we do a merge, we have to have an initial commit, so we'll make a dummy commit
dir > Read.md
git add .
git commit -m "initial commit"

# Add a remote for and fetch the old RepoA
git remote add -f RepoA https://github.com/DimitriDewaele/RepoA

# Do the same thing for RepoB
git remote add -f RepoB https://github.com/DimitriDewaele/RepoB

# Rebase the working branch (master) on top of repoB
git rebase RepoB/master

# Rebase the working branch (master with RepoB) on top op repoA
git rebase RepoA/master

Возможно ли иметь что-то вроде этого? (раскрашенное решение!!!)

Painted

Я хотел бы сохранить исходное время + историю слияния.

ОБНОВЛЕНИЕ - ОТВЕТ

Ответ, который работал лучше всего для меня, работал с точками трансплантата. Но другие ответы также очень полезны в других случаях использования. Я добавил свои результаты в github, поэтому каждый может оценить.

Ответ 1: Лучшая работа в моем случае "Трансплантат" показал правильный рабочий ответ для меня.

GitHub: RepoGraft

введите описание изображения здесь

Ответ 2 опция "replace" из "LeGEC" также дает хорошие результаты для некоторых вариантов использования. Одна аномалия осталась для меня:

GitHub: RepoHistory

введите описание изображения здесь

Ответ 3: стоит добавить. Ответ от "VonC". Я не мог получить вариант "-preserve-merges working" в моем случае. Это может работать в других сценариях, но я не тестировал этого furtner.

Ответы

Ответ 1

Как вы обнаружили, rebase - это не команда, которую вы хотите использовать для сшивания истории вместе (потому что она действительно перезаписывает историю). Ранняя Git имела функцию (хак), разработанную специально для того, что вы пытаетесь сделать: точки трансплантата. Еще лучше, с 1.6.5 вы можете использовать git replace --graft:

git checkout master
git replace --graft $(git log RepoB/master --format=%H | tail -1) HEAD
git replace --graft $(git log RepoA/master --format=%H | tail -1) RepoB/master
git reset --hard RepoA/master

(git log RepoA/master --format=%H | tail -1 возвращает начальную фиксацию из RepoA)

Технически вы можете пропустить первый replace, если в действительности master у вас нет ничего ценного, что даст только историю с RepoB + RepoA.

Эти команды создают записи в refs/replace/*, которые можно нажать и вытащить, чтобы поделиться пересмотренной историей с другими. Или, если вы не заботитесь о сохранении SHA для RepoA/RepoB, вы можете сделать замены постоянными, запустив git filter-branch --all, чтобы создать "реальный" набор коммитов желаемой линии.

Ответ 2

В git rebase есть два варианта, которые должны быть интересны вашему делу:

p
--preserve-merges

Воссоздание слияния вместо того, чтобы сплющить историю путем повторного воспроизведения, фиксирует введение слияния.

--committer-date-is-author-date 

(из git am)

По умолчанию команда записывает дату из сообщения электронной почты в качестве даты фиксации фиксации и использует время создания фиксации в качестве даты коммиттера. Это позволяет пользователю лгать о дате коммиттера, используя то же значение, что и дата автора.

Проверьте, если вторая перебаза не дает лучшего результата с:

git rebase -p --committer-date-is-author-date RepoA/master

Ответ 3

Этот ответ предлагает использовать другой способ RepoB в качестве активного репо и иметь доступ к истории RepoA:

использовать git replace

# start with a regular clone of the active repo :
$ git clone RepoB

# add repoA as a remote :
$ git remote add -f history https://github.com/DimitriDewaele/RepoA

# get hash of *initial* commit on repoB :
$ git log --oneline origin/master | tail -1
abcdef Initial commit

# get hash of last commit on repoA :
$ git log --oneline history/master | head -1
12345 Merge branch 'develop'

# use 'git replace' to tell git to stitch histories in the log :
$ git replace abcdef 12345

Примечание: эта операция выполняется на вашем компьютере, а не на удаленных репозиториях, поэтому ее следует повторять во всех новых клонов.

Вариант:

Вы можете нажать RepoA:master на RepoB под новым именем (например: RepoB:history/master), затем вы можете использовать git replace abcdef history/master, на коммит, которые все хранятся в RepoB.

Ответ 4

Попробуйте выполнить следующие шаги:

  • Создайте новый пустой репозиторий New.

  • Сделайте начальную фиксацию, потому что она нужна, прежде чем мы сможем слить.

  • Добавление удаленного старого хранилища OldA.

  • Объединить OldA/master с New/master.

  • Создайте подкаталог OldA.

  • Переместить все файлы в подкаталог OldA.
  • Зафиксировать все перемещения файла.
  • Повторите 3-6 для OldB.

A Powershell script для этих шагов может выглядеть так:

Предположим, что текущий каталог - это то место, где мы хотим создать новый репозиторий Создать новый репозиторий

$git init

Прежде чем мы сделаем слияние, мы должны иметь начальную фиксацию, так что сделаем фиктивный фиксатор

$dir > deleteme.txt $git добавить.

$git commit -m "Исходная фиктивная фиксация"

Добавьте пульт дистанционного управления и выберите старое репо

$git удаленный add -f old_a

Объединить файлы из old_a/master в новый /master

$git merge old_a/master

Очистите наш фиктивный файл, потому что нам он больше не нужен

$git rm.\deleteme.txt

$git commit -m "Очистить начальный файл"

Переместите файлы и папки old_a repo в подкаталог, чтобы они не столкнулись с другим репо, которое будет позже

$mkdir old_a

$dir -exclude old_a | % { git mv $_. Имя old_a}

Зафиксировать перемещение

$git commit -m "Переместить файлы old_a в subdir"

Сделайте то же самое для old_b

$git удаленный add -f old_b

$git merge old_b/master

$mkdir old_b

$dir -exclude old_a, old_b | % { git mv $_. Имя old_b}

$git commit -m "Переместить файлы old_b в subdir"

Передать ветку признаков из одного из старых репозиториев $git checkout -b функция не работает

$git merge -s recursive -Xsubtree = old_a old_a/feature-in-progress

Надеюсь, что это поможет.