2017-02-21 49 views
2

У меня есть репозиторий A (оригинальный), имеющий полный набор коммитов. В определенный момент времени было решено, что репозиторий A больше не будет использоваться, и новый чистый репозиторий B был создан с нуля, добавив все содержимое репо A, используя copy + paste (а не путем объединения содержимого A в чистый B, чтобы сохранить историю фиксации). То, что я хочу достичь сейчас, - это приклеить как фиксации репозиториев, так и историю (очень важно, чтобы история была склеена) в третьем новом чистом репозитории C. Конечная цель заключается в том, что репозиторий C должен содержать все изменения как из исходных репозиториев A, так и из B в хронологическом порядке, как если бы репозиторий B вообще не был создан, например а если работа протекала в хранилище А.Git: объединить два репозитория один над другим

Так что текущая ситуация:

репо A: совершить A1> A2 фиксации> фиксации A3> ...> Зафиксировать An

репо B: B1 совершить (= A1 + A2 + A3 + ... + An)> фиксации В2 (= совершить An + 1)> ...> совершить Bk

Пробовал следующие подходы:

git remote add -f A <repo_A_url> 
git merge A/master 
git remote add -f B <repo_B_url> 
git merge B/master 

Тогда разрешённых конфликтов , Частично работал с тех пор, как история каким-то образом была испорчена.

Тогда попробовал, я думаю, самый чистый подход - слияние только репо A в репо C, а затем перевернутый вихревой репо B в диапазоне от B2 ... Bk. Он работает, но фиксация слияния вишни замедляет процесс слияния.

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

Большое спасибо.

ответ

0

Вы можете вишни выбрать диапазон фиксации с помощью одной фиксации.

$ git merge A/master   # merge A/master into C/master 
$ git cherry-pick B2^..Bk  # cherry-pick all B2 to Bk commits 

Или, вы можете переустановить. Перейти к C repo master ветка. Вы можете оформить новый Banch (скажем, rebase), а затем объединить B/мастер и перебазировать его на A/master

$ git checkout -b rebase origin/master # checkout a new branch with clean C-remote/master history 

$ git merge B/master   # merge B/master into C/master 
$ git rebase A/master   # rebase C/master onto A/master 

Если все истории выглядит нормально, то замените master на rebase отрасли.

$ git checkout rebase   # make sure current branch is rebase 
$ git branch -D master   # delete local master branch 

$ git checkout -b master  # create & checkout a new 'master' branch  
$ git push -f orgin master  # update C-remote/master 
3

Если ваша история довольно линейна (т.е. просто master в каждом из А и В), это не будет слишком плохо. Если есть много филиалов, с которыми можно бороться, он будет более активным (см. Обновление ниже), но все же это обеспечило бы отправную точку:

Сначала создайте репозиторий C.

git clone /url/for/repo/A C 
cd C 

Теперь извлечь все объекты из B

git remote add B /url/for/repo/B 
git fetch B 

Теперь мы должны иметь обе истории в новом C репо.Rebase B репо совершает на историю

git rebase --onto master --root B/master 

Теперь вам необходимо обновить master реф и, возможно, очистить немного

git branch -f master 
git remote remove B 

Теперь А в списке, как ваш origin удаленный; вы, вероятно, либо хотите нажать на нее, либо удалить ее как источник, в зависимости от того, собираетесь ли вы использовать A для того, чтобы содержать все в будущем.

  • UPDATE: Хорошо, вот немного больше информации в случае, если ваша история не является линейным, так как он, вероятно, никогда это ... Сначала давайте сосредоточимся на топологии, то слово или два на рефов ...

Топология-накрест, на самом деле есть три общих сценария:

1) Филиалы и сливается в B

Так давайте предположим, что у вас есть один кончик ветви в B (если нет, прочитайте это, а затем просмотрите сценарий 2), который прослеживается до одного корня, который вы можете перенести на один кончик ветки в A (если не увидеть сценарий 3 ниже, вернитесь к этому) ,

A1 ---- A2 ---- A3 <--- (master) 
    \  /
    A4 -- A5 

--------------------------- 

B1 ---- B2 ---- B3 <--- (master) 
    \  /
    B4 -- B5 

Там, возможно, были филиалы в А, но в конечном счете они были объединены назад, и вы не должны беспокоиться о них. Там также могут быть ветви в B, и хотя они объединены обратно, они могут вызвать проблемы, если rebase попытается сделать их линейными.

Начните с создания C и импорта обеих историй, как мы это делали выше. (В конце я предлагаю небольшое изменение этой процедуры, имея отношение к refs ... но вернемся к этому.)

Теперь у вас есть два варианта. Простейшим далеко должен использовать filter-branch (но это может занять много времени). Найдите значение хэш-функции фиксации, на которую вы будете прививкой (помечено A3 выше) и запустить

git filter-branch --parent-filter 'sed "s/^\$/-p xxxxxxxxxx/"' B/master 

(где XXXXXXXXXX является хэш-значение).

Это предполагает, что у вас есть sed; он доступен в среде git bash в Windows или почти в любой системе * nix. Если нет, вы можете найти эквивалентный фильтр. (Все, что он делает, говорит: «Если ввод пустой строки, напишите« -p », за которым следует хеш, на который я пересаживаю, иначе передайте вход через мой вывод».)

Если для некоторых причина, по которой вы не можете этого сделать, или если это похоже на проблему с производительностью, тогда вы можете попробовать план b: дать --preserve-merges вариант rebase ... и это будет делать то, что вы хотите много времени. Но есть серьезные оговорки.

В принципе, если слияние внесло изменения вручную - либо потому, что руководство разрешение конфликтов было необходимо, или потому, что слияние было сделано с --no-commit и ручными изменениями были введены таким образом - то слияние не будет воспроизводиться должным образом перебазироваться даже с этой опцией.

В случае конфликта, перестановка должна прекратиться и позволить вам повторно применять ручные разрешения (что вы, возможно, сможете сделать с проверкой пути (checkout ... -- .) первоначального слияния, но в случае, если кто-то использовал --no-commit перебазироваться даже не поймет, ничего плохого.

Если вы знаете, что это будет проблемой, но может определить один или два проблема сливает, то один из вариантов является перебазирования каждого из родителей проблемного Merge, а затем переделывать слить вручную, затем продолжить с этой точки дальше.

Если вы не знаете, если/где p будут возникать ошибки, вы можете попробовать rebase, а затем выполнить проверку для сравнения коммитов. Перед тем, как перебазироваться

git checkout master 
git tag old-B-master 

Тогда попробуйте Rebase

git rebase --preserve-branches --onto master --root B/master 
git tag new-B-master 

Затем сделать то, что уровень проверки кажется безопасным для вас. (Очевидно, что дифф old-B-master против new-B-master, как минимум. Когда я сделал что-то вроде этого, я написал сценарий рекурсивно траверс коммита древностей сравнения фиксации по фиксации. Paranoid? Возможно.)

Если только это идет очень, очень гладко, вам, вероятно, лучше отказаться от подхода filter-branch.

2) Несколько советов филиалов в B

A1 ---- A2 ---- A3 <--- (master) 
    \  /
    A4 -- A5 

--------------------------- 

B1 ---- B2 <--- (master) 
    \ 
    B4 -- B5 <--- (branch1) 

Может быть, ваш B репо не полностью слиты. Это может или не может усложнить ситуацию. Если вы используете filter-branch, он может работать на многих ссылках одновременно. Вы, вероятно, не можете просто сказать --all (потому что это может уловить ссылки, которые уже находятся в дереве A, и, скорее всего, операция закончится неудачей), но вы можете перечислить подсказки ветки из дерева B.

git filter-branch --parent-filter 'sed "s/^\$/-p xxxxxxxxxx/"' B/master B/branch1 

Если вы пытаетесь использовать перебазироваться (или если вы просто хотите работать с одним наконечником исх), вы можете создать временный осьминога слияния.

git checkout B/master 
git checkout -b b-entry-point 
git merge -s ours B/branch1 B/branch2 ... 

В результате слияние происходит временно. (Вы можете удалить ветвь b-entry-point после трансплантата.) Она просто предоставляет единственную «точку входа» в дерево фиксации B.

3) Несколько советов филиалов в A

A --- Am <-- (master) 
    \ 
    Ab1 <-- (branch1) 
--------------------------------------- 
B1 ---- B2 <-- (master) 

B3 ---- B4 <-- (branch1) 

Так что, если не был полностью слиты в первую очередь? Когда вы создали репо B, вы только создать один новый фиксатор B === Am? Я так думаю, потому что вам пришлось бы сделать что-то странное, как несколько деревьев истории, чтобы включить представление Ab1, и у вас возникла бы небольшая головная боль, если вы захотите повторно объединить ...

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

Если у вас есть несколько привитых очков, но они с тех пор были вновь объединены в M, то вам, вероятно, придется прививать каждого из родителей M «s индивидуально, а затем воссоздать слияние как M', а затем продолжить прививкой детей от M до M'.

Хорошо, но как насчет ссылок?

Теперь вышесказанное в порядке, но у вас могут быть ссылки (в A и/или в B), о которых вы заботитесь, кроме как только ветка master.

Это одна из тех вещей, которые лучше всего обрабатываются filter-branch; на самом деле, если я правильно напомню, rebase не будет переписывать какой-либо референт, за исключением того, что его ветвление отбрасывается (а не даже если это удаленная ветка ref).

Особенно при использовании filter-branch, вы можете обнаружить, что удобно для создания C клонирования B и импорт удаленных рефов формы А (а не наоборот, как было показано выше), так что вы можете иметь filter-branch переписать локальные реф для вас ,

Несмотря на это, вы можете найти комбинацию удаленных ссылок, которые необходимо переместить. Команды ветви и тегов с параметром -f могут использоваться по мере необходимости, выравнивая локальные ссылки на любой удаленный реф, наиболее подходящий для вашего конечного состояния.

+0

В настоящее время я использую ваше решение, которое является лучшим на данный момент и которое я пробовал до использования подхода «вишневый выбор», но, как вы сказали, если есть больше филиалов, это будет более активно и от того, что я видя во время перезагрузки, часто встречаются конфликты слияния. Они очевидны из-за того, что rebase пытается линеаризовать (rebase) историю фиксации B при объединении ее поверх A. Если я ошибаюсь, скажите мне. Если это так, можно ли предотвратить процесс линеаризации? – Ivan

+0

Я добавлю несколько заметок о работе с несколькими ветвями; из первоначального вопроса я надеялся, что у вас просто была линейная история и ленился. –

+0

Несмотря на то, что обновление, которое я предоставил, может помочь, вы можете немного удержаться на втором обновлении ... Я думаю, что в некоторых случаях эти инструкции сделают беспорядок ref. –

 Смежные вопросы

  • Нет связанных вопросов^_^