Skip to content

Instantly share code, notes, and snippets.

@borekb
Last active February 12, 2018 09:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save borekb/eccc0af01f3b2c1d47bb7955a08bc214 to your computer and use it in GitHub Desktop.
Save borekb/eccc0af01f3b2c1d47bb7955a08bc214 to your computer and use it in GitHub Desktop.
A script to merge repositories. Used in blog post (CZ) https://borekb.cz/2017/01/monorepo/. Updated version: https://gist.github.com/borekb/b4aa4f97ccd826dce1d4793a0d54fd26
#!/bin/bash
# Merges child repo into target repo. Maintains branches and tags, filters history.
#
# Based on this amazing article: https://gofore.com/merge-multiple-git-repositories-one-retaining-history/
#---------------------------------
# Variables
#---------------------------------
TARGET_REPO='monorepo'
CHILD_REPO='microservice01'
NEW_PATH='subproject' # a subfolder in the target repo, `-` must be escaped as `\-`
BRANCH_TO_USE='123-merge-microservice01-repo'
TARGET_REPO_ISSUE='123'
RUN_CHILD_REPO_PROCESSING=true
RUN_REPO_MERGE=true
#---------------------------------
# Prepare the child repo
#---------------------------------
if [ "$RUN_CHILD_REPO_PROCESSING" = true ] ; then
cd $CHILD_REPO
# 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
# Filter the repo:
# 1. Move all files to a subdirectory named after the child repo. (Keeps branches and tags.)
# 2. Replaces [#123] with [versionpress/$CHILD_REPO#123].
# Test this with: echo '#1 [#123] issue #2 other/repo#12 [other/repo#12]' | sed -r 's/( |\[|^)#([0-9]+)/\1versionpress\/CHILDREPO#\2/g'
git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&'$NEW_PATH'/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' --tag-name-filter cat --msg-filter 'sed -r '\''s/( |\[|^)#([0-9]+)/\1versionpress\/'$CHILD_REPO'#\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 ..
fi
#---------------------------------
# Merge the repos
#---------------------------------
if [ "$RUN_REPO_MERGE" = true ] ; then
cd $TARGET_REPO
git checkout -b $BRANCH_TO_USE
git remote add -f $CHILD_REPO ../$CHILD_REPO
git merge --allow-unrelated-histories -m "[#$TARGET_REPO_ISSUE] Merge $CHILD_REPO repo" $CHILD_REPO/master
git remote rm $CHILD_REPO
fi
#---------------------------------
# Push
#---------------------------------
# After manually inspecting:
# git push origin $BRANCH_TO_USE
@borekb
Copy link
Author

borekb commented Feb 12, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment