Skip to content

Instantly share code, notes, and snippets.

@borekb
Created February 12, 2018 09:13
Show Gist options
  • Save borekb/b4aa4f97ccd826dce1d4793a0d54fd26 to your computer and use it in GitHub Desktop.
Save borekb/b4aa4f97ccd826dce1d4793a0d54fd26 to your computer and use it in GitHub Desktop.
Script to merge repositories. Updated version of the original Gist https://gist.github.com/borekb/eccc0af01f3b2c1d47bb7955a08bc214
#!/bin/bash
# Repo merge script used to merge OLD_REPO into TARGET_REPO.
# Based on https://gofore.com/merge-multiple-git-repositories-one-retaining-history/
# How to use:
#
# 1. Create a temp directory
# 2. Checkout TARGET_REPO and OLD_REPO there
# 3. Put this script into the temp directory, side by side with the repos.
# 4. Inspect the script so that you know what you're running, and update if necessary.
# 5. Make sure that the OLD_REPO only has the `master` branch and all others have been merged / deleted.
# 6. Run it (usually with RUN_PUSH disabled)
# 7. Inspect the results, push to GitHub if all was OK
#---------------------------------
# Variables
#---------------------------------
GITHUB_OWNER='versionpress'
TARGET_REPO='versionpress' # path relative to this script
OLD_REPO='docs' # path relative to this script
OLD_REPO_ESCAPED='docs' # path relative to this script
NEW_PATH_ESCAPED='docs' # a subfolder in the target repo; escepa `-` as `\-`
BRANCH_TO_USE='123-merge-repo'
TARGET_REPO_ISSUE='123'
# flags that enable / disable certain sections of this script
RUN_OLD_REPO_PROCESSING=true
RUN_REPO_MERGE=true
RUN_PUSH=false # inspect everything before running this! or perhaps do it manually
#---------------------------------
# Prepare the child repo
#---------------------------------
if [ "$RUN_OLD_REPO_PROCESSING" = true ]
then
cd "$OLD_REPO" || exit
# Create local branches
remote=origin ; for brname in $(git branch -r | grep $remote | grep -v master | grep -v HEAD | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'); do git branch "$brname" $remote/"$brname"; done
# Remove remote branches (`/remotes/origin/*` refs)
git remote remove origin
# Remove all tags
git tag | xargs git tag -d
# Filter out `exampledir`
#git filter-branch --tag-name-filter cat --index-filter 'git rm -r --cached --ignore-unmatch exampledir' --prune-empty -f -- --all
# Filter paths so it looks like the commits always went to a path in the target repo.
git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&'$NEW_PATH_ESCAPED'/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' --tag-name-filter cat -f -- --all
# Replace `#123` with `owner/oldrepo#123`
# Test with: echo '#1 [#123] (#123) issue #2 other/repo#12 [other/repo#12]' | sed -r 's/(\W|^)#([0-9]+)/\1owner\/oldrepo#\2/g'
git filter-branch --tag-name-filter cat --msg-filter "sed -r 's/(\\W|^)#([0-9]+)/\\1$GITHUB_OWNER\\/$OLD_REPO_ESCAPED#\\2/g'" -f -- --all
# Clean up the `original` refs that Git keeps as a backup
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
cd .. || exit
fi
#---------------------------------
# Merge the repos
#---------------------------------
if [ "$RUN_REPO_MERGE" = true ]
then
cd $TARGET_REPO || exit
git checkout -b $BRANCH_TO_USE
git remote add -f $OLD_REPO ../$OLD_REPO
git merge --allow-unrelated-histories -m "[#$TARGET_REPO_ISSUE] Merge $OLD_REPO repo" $OLD_REPO/master
git remote rm $OLD_REPO
fi
#---------------------------------
# Push
#---------------------------------
# After manually inspecting:
if [ "$RUN_PUSH" = true ]
then
git push origin $BRANCH_TO_USE
fi
cd .. || exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment