Это действительно не очень хороший ответ, так как он больше касается сценария, который вы использовали - или, может быть, я должен сказать, сценарий, который вы не использовали, как ваш комментарий говорит, что вы использовали один на основе сценария, с которым вы связали - но я покажу довольно запутанный график, который я получаю в гипотетическом сценарии-преобразовании некоторых оригинальных репозиториев ниже. Обратите внимание, что этот конкретный скрипт оставляет все преобразования с фиксацией базы слияния, по сути, commit B
, а сам коммит B
имеет значение empty .
Ваш вопрос говорит:
Теперь я хочу объединить ветвь source
в ветвь target
, отметив, что я убедился, что они были синхронизированы прямо перед финальным переключением.
Как вы увидите ниже, все новые ветви названы в честь проекта, из которого они вышли - нет четкого способа сопоставить source
и target
, например, P или Q. Но если бы вы бежать:
git checkout P/master
git merge Q/master
после процесса, показанного ниже, база слияния для этого git merge
будет пустой-фиксацией- B
, и слияние будет проходить гладко: Git будет смотреть на коммиты, которые я нарисовал, как D
и H
соответственно , проследите их предков, найдите коммит B
в качестве их базы слияния и выполните два git diff
s:
git diff <hash-of-B> <hash-of-D> # what we did on P/master
git diff <hash-of-B> <hash-of-H> # what they did on H/master
Вывод этих git diff
s говорит о том, что каждый файл создается с нуля , и все их имена различны: все в P/master
называется P/*
и все в H/master
назван Q/*
. Не было бы конфликтов имен, и слияние завершилось бы самостоятельно.
Очевидно, это не то, что вы делаете, тогда. Но то, что вы делаете и какой коммит является базой слияния, остается загадочным. Похоже, что вы выбираете два коммитов-подсказок, так что база слияния двух коммитов-подсказок является коммитом, в котором имеет файлы, и эти файлы еще не переименованы из базы на чаевые.
Смысл сценария, который вы связали, состоит в том, чтобы настроить все так, чтобы базы слияния каждого из несвязанных проектов представляли собой пустой коммит. Вероятно, что нужно сделать после этого сценария - или вместо этого сценария - сделать одно массивное слияние осьминога со всеми последними коммитами (примечание: это не проверено, что, вероятно, очевидно):
git checkout P/master # just to be somewhere that's not master
git branch -d master # discard existing master branch name
git checkout --orphan master # arrange to create new master
git merge P/master Q/master R/master # make big octopus merge to marry all projects
Базой слияния этого слияния осьминога снова будет фиксация B
, а результатом будет одно слияние, в котором все проекты будут под новыми именами project/*
. Все исходные репозитории теперь в основном бесполезны, хотя, если в них есть новые коммиты, вы можете извлечь их, добавить коммит переименования и объединить с коммитом переименования (это было бы проще, если бы скрипт импорта этого не делал удалить добавленные пульты).
Наблюдения за работой связанного скрипта
Я никогда не сталкивался с этой конкретной проблемой, но подход в сценарии выглядит как неоправданная отправная точка. Вероятно, я бы сделал это немного по-другому, не беспокоясь о пустой базе слияния и используя git read-tree
и git commit-tree
для создания и создания конечного слияния осьминога. Основной ключ заключается в добавлении коммита переименования в конце каждой входящей ветви проекта (P/*
, Q/*
и т. Д.) В скриншоте ниже.
Сценарий, кажется, работает таким образом. Он имеет в качестве входных данных проекты P, Q, R (URL-адреса, последний компонент которых обрабатывается именем проекта).
- Сделать пустой репо.
Сделать два начальных коммита:
A--B <-- master
У коммита А один файл, у коммита Б нет файлов (почему бы не просто
зафиксировать пустое дерево как B? но не берите в голову).
Цикл, для всех трех проектов. Здесь я расширил цикл для просмотра
что происходит.
(итерация цикла 1) git remote add P <url>
и git fetch P
(с --tags
!?). Здесь мы предполагаем, что у P есть master и dev.
A--B <-- master
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
Используйте git ls-remote --heads, чтобы найти имена для коммитов в P, т.е.
тот же набор имен у нас в refs/remotes/P/*
. (Предполагается, что
удаленный hsaне изменяется во время выборки - неразумно, но, вероятно, в порядке.)
Цикл над этими именами. Результат снова развернут в строке для иллюстрации ...
Выполнить git checkout -b P/master master
. Эффект:
A--B <-- master, P/master
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
Выполнить git reset --hard
без видимой причины: безрезультатно. возможно
это может оказать некоторое влияние на более поздний шаг.
Выполнить git clean -d --force
без видимой причины: без последствий.
Выполнить git merge --allow-unrelated-histories --no-commit remotes/P/master"
(does merge, but does not commit yet) and then run
git commit -m ... `.
Эффект:
A--B <-- master
\
\-------C <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
Возможно, переименуйте файлы с несколько коротким кодом (строки 160-180):
если проект P имеет один каталог верхнего уровня с именем P, ничего не делать, в противном случае
создать каталог с именем P (без проверки, если это не удается) и
тогда в силу:
git mv all-but-P P/
git commit -m "[Project] Move ${sub_project} files into sub directory"
дает:
A--B <-- master
\
\-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
Обратите внимание, что git mv
дается -k
, так что он ничего не делает, если
одна из операций git mv
не удалась бы. Однако кроме
для подкаталога P и .git
, все файлы верхнего уровня
рабочего дерева должно быть в индексе, а git mv
должно
успешно, если один из них не назван P
(в этом случае, yikes!).
Я предполагаю, что мы сделали mv, в противном случае D
не существует.
Повторите цикл (см. Шаг 5) для dev
. Выполнить git checkout -b P/dev master
:
A--B <-- master, P/dev
\
\-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
Предположительно безрезультатно git reset
и git clean
снова
как в шагах 7 и 8. (Это может что-то сделать, если git mv
в шаге 10 все пошло очень плохо?) Смешное двухступенчатое слияние, как в
шаг 9, давая:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
\ Pd <-- origin/P/dev
\ \
\---E <-- P/dev
где линия вниз от B соединяется с линией вверх от E.
На этом этапе график вышел из-под контроля.
Переименуйте и подтвердите, как в шаге 10. Я предполагаю, что
проект не находится в подкаталоге, в обоих master
, как
уже принято и dev
.
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
\ Pd <-- origin/P/dev
\ \
\---E--F <-- P/dev
Действительно безобразная попытка переименовать теги в строках 190-207. это
должно было быть сделано во время получения, используя умный refspec.
Кто бы ни написал это, вероятно, не знал аннотированных против
легкие метки Мне не ясно, работает ли это
правильно и я не присматривался. Давайте просто предположим, что нет тегов
на данный момент.
Удалить удаленный P. Это также удаляет имена origin/P/*
,
но, конечно, коммиты остаются вокруг, как они удерживаются
новые P/*
филиалы:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
Повторите внешний цикл (шаг 3) с удаленным Q. Мы добавим Q и
получить (снова с --tags
, плохой план, как отмечено в шаге
14, но давайте просто предположим, нет тегов). Так что теперь мы получаем еще
непересекающийся подграф с origin/Q/*
именами. Для простоты
давайте просто предположим, что на этот раз существует только origin/Q/master
:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
Q1-Q2-...-Qm <-- origin/Q/master
Выполнить git checkout -b Q/master master
:
A--B <-- master, Q/master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
Q1-Q2-...-Qm <-- origin/Q/master
Запустить (вероятно, неэффективно и все еще загадочно)
git reset --hard
и git clean
шагов.
Используйте смешное двухступенчатое слияние с --allow-unrelated-histories
создать новый коммит G
, например:
---------------G <-- Q/master
/ |
A--B <-- master | (down to Qm)
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
/ (up to G)
/
Q1-Q2-...-Qm <-- origin/Q/master
Опять же, необязательно: переименуйте все файлы в G, чтобы жить в Q / и
совершить. Снова давайте предположим, что это происходит:
---------------G--H <-- Q/master
/ |
A--B <-- master | (down to Qm)
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
/ (up to G)
/
Q1-Q2-...-Qm <-- origin/Q/master
Уродливая попытка переименовать теги; мы проигнорируем это.
Удаление удаленных имен Q
и origin/Q/*
. (Не нужно рисовать это.)
Повторите внешний цикл для хранилища R. Предполагая, что он имеет только
его собственный master
, мы получим запутанный граф, подобный этому:
--------------------I--J <-- R/master
/ | (down to Rm)
/
| ---------------G--H <-- Q/master
|/ |
A--B <-- master | (down to Qm)
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
/ (up to G)
/
Q1-Q2-...-Qm
/ (up to I)
/
R1-R2-...----Rm
(конец анализа)