Skip to content

Instantly share code, notes, and snippets.

@serguk89
Created October 5, 2023 09:18
Show Gist options
  • Save serguk89/0087f1d7337555c3db383aa5edd268ab to your computer and use it in GitHub Desktop.
Save serguk89/0087f1d7337555c3db383aa5edd268ab to your computer and use it in GitHub Desktop.
Creates a new monorepofrom multiple monolit repositories
#!/bin/sh
# Creates a new monorepo by fusing multiple repositories
# Child repositories that are going to be fused
CHILDREN="wp/theme/master plugins/gutenblocks/master wp/theme-core/master"
# Name of the created monorepo
MONOREPO="monorepo"
# Exit in case of any error
set -e
# Be verbose
set -x
# create the monorepo
mkdir $MONOREPO
cd $MONOREPO
git init
# Create a first commit. A first commit is needed in order to be able to merge into master afterwards
echo "*~" >.placeholder
git add .placeholder
git commit -m "Initial"
git rm .placeholder
git commit -m "Remove placeholder file"
# Add remotes for all children
for repo in $CHILDREN; do
repo=$(echo $repo | cut --delimiter / --fields=1,2,3)
remote=${repo##*/}
git remote add "${remote}" "git@gitlab.co:user/${repo}.git"
done
# Fetch all child repositories
git fetch --all
# Checkout all the master branches of the child repositories
for repo in $CHILDREN; do
branch=$(echo $repo|rev| cut -f 1 -d "/" | rev)
remote=$(echo $repo|rev| cut -f 2 -d "/" | rev)
git checkout -f -b "${remote}_master" "${remote}/${branch}"
# Rewrite history to move all repo files into a subdirectory
export SUBDIRECTORY="${remote}"
git filter-branch -f --index-filter '
git ls-files -s | sed "s|\t|&${SUBDIRECTORY}/|" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && if [ -f "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' --
done
# Switch back to our master branch
git checkout -f master
# Merge all the repositories in our master branch.
for repo in $CHILDREN; do
remote=$(echo $repo | rev | cut -f 2 -d "/" | rev)
git merge --no-commit --allow-unrelated-histories "${remote}_master"
git commit -a -m "Merge ${remote} in subdir"
done
# remove all child repo branches and remotes
for repo in $CHILDREN; do
remote=$(echo $repo | rev | cut -f 2 -d "/" | rev)
git branch -D "${remote}_master"
git remote remove "${remote}"
done
# prune all history and do an aggressive gc
git reflog expire --expire=now --all && git gc --prune=now --aggressive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment