Слияние двух репозиториев Git без нарушения истории файлов
мне нужно объединить два репозитория Git в совершенно новый, третий репозиторий. Я нашел много описаний того, как это сделать с помощью слияния поддеревьев (например, ответ Якуба Нарембского о том, как вы объединяете два репозитория Git?) и следование этим инструкциям в основном работает, за исключением того, что когда я фиксирую слияние поддерева, все файлы из старых репозиториев записываются как новые добавленные файлы. Я могу видеть историю фиксации из старых репозиториев, когда я делаю git log, но если я это сделаю git log <file> он показывает только одну фиксацию для этого файла-слияние поддеревьев. Судя по комментариям к приведенному выше ответу, я не одинок в этой проблеме, но я не нашел для нее опубликованных решений.
есть ли способ объединить репозитории и оставить историю отдельных файлов нетронутой?
5 ответов:
вот пример сценария Powershell для склеивания двух репозиториев:
# 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 > deleteme.txt git add . git commit -m "Initial dummy commit" # Add a remote for and fetch the old repo git remote add -f old_a <OldA repo URL> # Merge the files from old_a/master into new/master git merge old_a/master --allow-unrelated-histories # Clean up our dummy file because we don't need it any more git rm .\deleteme.txt git commit -m "Clean up initial file" # Move the old_a repo files and folders into a subdirectory so they don't collide with the other repo coming later mkdir old_a dir -exclude old_a | %{git mv $_.Name old_a} # Commit the move git commit -m "Move old_a files into subdir" # Do the same thing for old_b git remote add -f old_b <OldB repo URL> git merge old_b/master --allow-unrelated-histories mkdir old_b dir –exclude old_a,old_b | %{git mv $_.Name old_b} git commit -m "Move old_b files into subdir"очевидно, что вы могли бы вместо этого объединить old_b в old_a (который становится новым комбинированным РЕПО), если вы предпочитаете это делать – измените скрипт в соответствии с требованиями.
Если вы хотите, чтобы принести в процессе ветви функции, а также, используйте это:
# Bring over a feature branch from one of the old repos git checkout -b feature-in-progress git merge -s recursive -Xsubtree=old_a old_a/feature-in-progressэто единственная неочевидная часть процесса-это не слияние поддеревьев, но скорее аргумент к обычному рекурсивному слиянию, который говорит Git, что мы переименовали цель, и это помогает Git выровнять все правильно.
Я написал немного более подробное объяснение здесь.
вот способ, который не переписывает историю, поэтому все идентификаторы фиксации останутся действительными. Конечным результатом является то, что файлы второго РЕПО окажутся в подкаталоге.
добавить второе РЕПО в качестве удаленного:
cd firstgitrepo/ git remote add secondrepo username@servername:andsoonубедитесь, что вы загрузили все коммиты secondrepo:
git fetch secondrepoсоздайте локальную ветвь из ветви второго РЕПО:
git branch branchfromsecondrepo secondrepo/masterпереместить все его файлы в подкаталог:
git checkout branchfromsecondrepo mkdir subdir/ git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} subdir/ git commit -m "Moved files to subdir/"объединить вторую ветвь в главную ветвь первого РЕПО:
git checkout master git merge --allow-unrelated-histories branchfromsecondrepoваш репозиторий будет иметь более одного корневого коммита, но это не должно создавать проблем.
пожалуйста, посмотрите на использование
git rebase --root --preserve-merges --ontoчтобы связать две истории в начале их жизни.
Если у вас есть пути, которые пересекаются, исправить их с
git filter-branch --index-filterкогда вы используете журнал, убедитесь, что вы" найти копии сложнее " с
git log -CCтаким образом, вы найдете любые движения файлов в пути.
Я повернул решение из @Flimm это в
git aliasвот так (добавлено к моему~/.gitconfig):[alias] mergeRepo = "!mergeRepo() { \ [ $# -ne 3 ] && echo \"Three parameters required, <remote URI> <new branch> <new dir>\" && exit 1; \ git remote add newRepo ; \ git fetch newRepo; \ git branch \"\" newRepo/master; \ git checkout \"\"; \ mkdir -vp \"${GIT_PREFIX}\"; \ git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} \"${GIT_PREFIX}\"/; \ git commit -m \"Moved files to '${GIT_PREFIX}'\"; \ git checkout master; git merge --allow-unrelated-histories --no-edit -s recursive -X no-renames \"\"; \ git branch -D \"\"; git remote remove newRepo; \ }; \ mergeRepo"
эта функция клонирует удаленное РЕПО в локальное РЕПО dir:
function git-add-repo { repo="" dir="$(echo "" | sed 's/\/$//')" path="$(pwd)" tmp="$(mktemp -d)" remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')" git clone "$repo" "$tmp" cd "$tmp" git filter-branch --index-filter ' git ls-files -s | sed "s,\t,&'"$dir"'/," | GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE" ' HEAD cd "$path" git remote add -f "$remote" "file://$tmp/.git" git pull "$remote/master" git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master" git remote remove "$remote" rm -rf "$tmp" }Как использовать:
cd current/package git-add-repo https://github.com/example/example dir/to/saveпрофит!
Comments