I need to merge two Git repos, Repo1 and Repo2, into a new single repository MonoRepo. The two repos have almost identical folder structures, and many files are very similar or even the same between the repos (the ultimate goal here is to unify and de-duplicate code). If that matters, both were originally created as branches in SVN, with Repo2 initially a copy of Repo1.
To merge them keeping the commit history, I am following 2 examples: example 1 and example 2.
The basic steps I follow are:
Prepare Repo1 and Repo2 by creating top-level folders ("Repo1" and "Repo2", respectively) and moving everything into them with
git mv
. This ensures that the repos have parallel folder structures without any overlap. Thus, Repo1's folder structure is transformed from:dir1/ file1 dir2/ file2 ...
to:
Repo1/ dir1/ file1 dir2/ file2 ...
and similarly Repo2 has "Repo2" as the top folder.
Create empty MonoRepo
Bring Repo1 and Repo2 in as remotes:
git remote add -f Repo1 ../Repo1 git remote add -f Repo2 ../Repo2
Merge them in using the
--allow-unrelated-histories
flag:git merge Repo1/main --allow-unrelated-histories git merge Repo2/main --allow-unrelated-histories
The problem is that merging in Repo2 creates a ton of rename/delete, modify/delete and rename/rename conflicts, for example:
CONFLICT (rename/rename): dir1/file1 renamed to Repo1/dir1/file1 in HEAD and to Repo2/dir1/file1 in Repo2/main.
Naively, I thought that since the folder structures of Repo1 and Repo2 are strictly non-overlapping, there should be no conflicts. However, it seems Git is keeping track of directory renaming, or is otherwise attempting to match directories that seem to have been renamed -- git merge
output starts with:
Performing inexact rename detection: 100% (1037700/1037700), done.
I am guessing this matching is particularly problematic in my case: the content of the repos is so similar that Git may think that many parts of Repo2 have been renamed from Repo1.
Based on a post "Renaming and Deep Directory Hierarchies in Git" I have tried 2 things to overcome the conflicts:
Set the
merge.directoryRenames
setting from default ("conflict") to "true" which would seem to allow to "just have such files moved to the new directory" withgit config --local merge.directoryRenames true
Create an empty top-level "Repo1" folder in the Repo2 repo, so that Git does not think that "Repo2" is a rename of "Repo1":
Repo1/ .gitkeep Repo2/ dir1/ file1 dir2/ file2 ...
Neither of these workarounds worked -- I am still getting hundreds of CONFLICT messages.
Any suggestions for this seemingly straightforward merge of two repos with parallel folder structures and similar content?
Thank you
I need to merge two Git repos, Repo1 and Repo2, into a new single repository MonoRepo. The two repos have almost identical folder structures, and many files are very similar or even the same between the repos (the ultimate goal here is to unify and de-duplicate code). If that matters, both were originally created as branches in SVN, with Repo2 initially a copy of Repo1.
To merge them keeping the commit history, I am following 2 examples: example 1 and example 2.
The basic steps I follow are:
Prepare Repo1 and Repo2 by creating top-level folders ("Repo1" and "Repo2", respectively) and moving everything into them with
git mv
. This ensures that the repos have parallel folder structures without any overlap. Thus, Repo1's folder structure is transformed from:dir1/ file1 dir2/ file2 ...
to:
Repo1/ dir1/ file1 dir2/ file2 ...
and similarly Repo2 has "Repo2" as the top folder.
Create empty MonoRepo
Bring Repo1 and Repo2 in as remotes:
git remote add -f Repo1 ../Repo1 git remote add -f Repo2 ../Repo2
Merge them in using the
--allow-unrelated-histories
flag:git merge Repo1/main --allow-unrelated-histories git merge Repo2/main --allow-unrelated-histories
The problem is that merging in Repo2 creates a ton of rename/delete, modify/delete and rename/rename conflicts, for example:
CONFLICT (rename/rename): dir1/file1 renamed to Repo1/dir1/file1 in HEAD and to Repo2/dir1/file1 in Repo2/main.
Naively, I thought that since the folder structures of Repo1 and Repo2 are strictly non-overlapping, there should be no conflicts. However, it seems Git is keeping track of directory renaming, or is otherwise attempting to match directories that seem to have been renamed -- git merge
output starts with:
Performing inexact rename detection: 100% (1037700/1037700), done.
I am guessing this matching is particularly problematic in my case: the content of the repos is so similar that Git may think that many parts of Repo2 have been renamed from Repo1.
Based on a post "Renaming and Deep Directory Hierarchies in Git" I have tried 2 things to overcome the conflicts:
Set the
merge.directoryRenames
setting from default ("conflict") to "true" which would seem to allow to "just have such files moved to the new directory" withgit config --local merge.directoryRenames true
Create an empty top-level "Repo1" folder in the Repo2 repo, so that Git does not think that "Repo2" is a rename of "Repo1":
Repo1/ .gitkeep Repo2/ dir1/ file1 dir2/ file2 ...
Neither of these workarounds worked -- I am still getting hundreds of CONFLICT messages.
Any suggestions for this seemingly straightforward merge of two repos with parallel folder structures and similar content?
Thank you
Share Improve this question edited Feb 7 at 8:32 dani-vta 6,9207 gold badges49 silver badges65 bronze badges asked Feb 6 at 17:35 user2690051user2690051 1751 gold badge1 silver badge9 bronze badges1 Answer
Reset to default 0If your goal is to bring the history of two repositories (I assume their master
branch) into a third new repo, you could use a different approach that relies on merging with the -X subtree=<path>
option. This flag allows you to prefix or strip a subfolder to make the trees match.
In your case, you could enter:
# create repository monorepo
mkdir monorepo
cd monorepo
git init
# create mock files to track and inlcude the subfolder paths in the repo.
# This step step is important to let subtree accept the paths.
mkdir repo1
mkdir repo2
echo "readme repo1" >> repo1/README.md
echo "readme repo2" >> repo2/README.md
git add .
git commit -m "init commit to include repo1 and repo2 paths in the repo"
# add remote for repo1 and fetch its master branch
git remote add origin_repo1 <repo1>
git fetch origin_repo1 master
# add remote for repo2 and fetch its master branch
git remote add origin_repo2 <repo2>
git fetch origin_repo2 master
# merging repo1 into the subfolder repo1
git merge --allow-unrelated-histories -s ort -X subtree="repo1/" origin_repo1/master
# merging repo2 into the subfolder repo2
git merge --allow-unrelated-histories -s ort -X subtree="repo2/" origin_repo2/master