I've been able to do the merge by building on the blog post suggested by Michael. The original post only takes care of merging the master branch - I've expanded it to pull all branches from the merged repos so no history is lost.
To reiterate, I've found many other suggested methods of doing this sort of merge, but none which both save the history and don't rename paths (causing Xcode to fail showing history).
# Init a git repo which will contain the merge of the two repos, each in its own subdirectory
cd ~/dev
mkdir Merged
cd Merged
git init
# Dummy initial commit to create a master branch
git commit --allow-empty -m "Initial commit"
# Clone first repo
cd ..
git clone <RepoA url>
cd RepoA
# Checkout all branches
for remote in `git branch -r | grep -v master `; do git checkout --track $remote ; done
# Prepend subdirectory to all committed files paths in all branches
git filter-branch -f --prune-empty --tree-filter ' mkdir -p .sub;
find . -mindepth 1 -exec mv {} .sub;
mv .sub RepoA
' -- --glob=refs/heads/*
# Garbage cleanup
git gc --aggressive
# Same steps for second repo
cd ..
git clone <RepoB URL>
cd RepoB
# Checkout all branches
for remote in `git branch -r | grep -v master `; do git checkout --track $remote ; done
# Prepend subdirectory to all committed files paths in all branches
git filter-branch -f --prune-empty --tree-filter ' mkdir -p .sub;
find . -mindepth 1 -exec mv {} .sub;
mv .sub RepoB
' -- --glob=refs/heads/*
# Garbage cleanup
git gc --aggressive
# Merge modified repos into unified repo
cd ../Merged
git remote add RepoA ../RepoA
git remote add RepoB ../RepoB
git fetch --all
for remote in `git branch -r`; do git checkout -b $remote --track $remote ; done
# Merge wanted branches (usually master) from each original repo into the master branch of the unified repo
git checkout master
git merge RepoA/master
git merge RepoB/master
# Remove remotes
git remote rm RepoA
git remote rm RepoB
# Garbage cleanup
git gc --aggressive
# All done
# Optionally push into a new empty remote repository
git remote add RepoMerged <Merged Repo URL>
git push --all RepoMerged