Skip to content

Instantly share code, notes, and snippets.

@coisa
Created August 15, 2023 22:48
Show Gist options
  • Select an option

  • Save coisa/d8115aac022c9ed836b6a8db3323dca4 to your computer and use it in GitHub Desktop.

Select an option

Save coisa/d8115aac022c9ed836b6a8db3323dca4 to your computer and use it in GitHub Desktop.
Convert GIT repository monorepo path into a submodule of an external repository
#!/bin/bash
#########################################################################################
# SCRIPT: Git Monorepo Splitter
#
# DESCRIPTION:
# This script is designed to help teams and individuals transition from a monorepo
# (a single repository containing multiple projects or directories) to a multi-repo setup
# (each project or directory in its own repository). The primary function is to take a
# directory from a monorepo and transform it into its own standalone repository, while
# maintaining its git history.
#
# A common scenario is when a particular project or directory within a monorepo grows
# to a point where it makes sense to manage it separately, or when different teams need
# to focus on different parts of a monorepo without interfering with each other.
#
# ADVANTAGES OF SPLITTING A MONOREPO:
# 1. **Focused Repositories:** Each repository has a clear and specific purpose.
# 2. **Independent Development Cycles:** Projects can evolve, release, and scale at their own pace.
# 3. **Reduced Complexity:** Developers can focus on a specific project without sifting through unrelated code.
# 4. **Enhanced Access Control:** Limit access based on project-specific needs.
# 5. **Optimized CI/CD:** Build and deploy processes can be tailored for each project.
# 6. **Modularity:** Encourages development of modular and decoupled systems.
#
# USAGE:
# ./convert-path-into-submodule.sh <REPOSITORY_URL> <BRANCH_NAME> <SUBMODULE_REPOSITORY_URL> <SUBMODULE_ROOT_DIRECTORY>
# (See the 'Usage' section within the script for argument details.)
#
# NOTE: Ensure Git LFS is installed if you're dealing with large files.
#########################################################################################
# Check if the necessary number of arguments are passed
if [ "$#" -ne 4 ]; then
echo "Usage: $0 <REPOSITORY_URL> <BRANCH_NAME> <SUBMODULE_REPOSITORY_URL> <SUBMODULE_ROOT_DIRECTORY>"
echo
echo "Arguments:"
echo " REPOSITORY_URL URL of the original repository from which you want to isolate a directory."
echo " BRANCH_NAME Name of the new branch that will be created based on the master (or main) branch."
echo " SUBMODULE_REPOSITORY_URL URL of the new empty repository where the isolated directory will be pushed."
echo " SUBMODULE_ROOT_DIRECTORY Path of the directory in the original repository that you want to isolate as a submodule."
exit 1
fi
# Assign arguments to variables
REPOSITORY_URL="$1"
BRANCH_BASE="master" # This can be changed to "main" or any other default branch name if needed
BRANCH_NAME="$2"
SUBMODULE_REPOSITORY_URL="$3"
SUBMODULE_ROOT_DIRECTORY="$4"
# Check if Git LFS is installed
if ! command -v git-lfs &> /dev/null
then
echo "Error: git-lfs is not installed. Please install it before running the script."
exit 1
fi
# Use system temporary directory
TMP_DIR=${TMPDIR:-/tmp}
WORK_DIR="$TMP_DIR/repo_$(date +%Y%m%d%H%M%S)"
mkdir $WORK_DIR
# Clone the original repository to the temporary directory
git lfs clone $REPOSITORY_URL $WORK_DIR
cd $WORK_DIR
# Create a new branch for the submodule
git checkout -b ${BRANCH_NAME}-submodule $BRANCH_BASE
# Isolate directory
git filter-branch --prune-empty --subdirectory-filter $SUBMODULE_ROOT_DIRECTORY ${BRANCH_NAME}-submodule
# Migrate LFS pointers (if required)
git lfs migrate export --everything
# Add new remote repository and push the branch
git remote add new-repo $SUBMODULE_REPOSITORY_URL
git push new-repo ${BRANCH_NAME}-submodule:$BRANCH_NAME
# Reset to the original branch and set up the submodule
git checkout $BRANCH_BASE
git checkout -b $BRANCH_NAME $BRANCH_BASE
git rm -r $SUBMODULE_ROOT_DIRECTORY
git commit -m "Removing $SUBMODULE_ROOT_DIRECTORY to convert into a submodule"
git submodule add $SUBMODULE_REPOSITORY_URL $SUBMODULE_ROOT_DIRECTORY
git commit -m "Adding $SUBMODULE_ROOT_DIRECTORY as a submodule"
git push origin $BRANCH_NAME
# Cleanup
cd ..
rm -rf $WORK_DIR
echo "Process completed!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment