Skip to content

Instantly share code, notes, and snippets.

@warting
Created June 14, 2023 14:21
Show Gist options
  • Save warting/fc5dca84e5af8419e66eefc5c249c566 to your computer and use it in GitHub Desktop.
Save warting/fc5dca84e5af8419e66eefc5c249c566 to your computer and use it in GitHub Desktop.
Script to automate the process of absorbing a standalone Git repository into a monorepo while preserving history, and handling submodules if they exist.
#!/usr/bin/env bash
# This script is used to absorb one git repository into another, making the absorbed
# repository a subdirectory within a monorepo. It allows for easy merging of multiple
# repositories into a monolithic structure (monorepo) while preserving each repository's
# git history. This is useful when you want to consolidate your repositories into a single
# repository for easier management and tracking.
#
# The script works as follows:
# 1. It clones the repositories to be merged into temporary directories.
# 2. Prepares the repository to be absorbed by moving its content into a subdirectory.
# 3. Removes unnecessary git files that may conflict with the target monorepo.
# 4. Moves to the monorepo, and if the path where the repository is to be absorbed already exists, it is removed.
# 5. Adds the old repository as a remote to the monorepo.
# 6. Merges the repository to be absorbed into the monorepo.
# 7. Pushes the changes to the monorepo.
# 8. Cleans up the temporary directories used during the process.
#
# Usage:
# ./merge_into_monorepo.sh <repository_to_absorb_from> <repository_to_absorb_into> <path_in_monorepo>
#
# Example:
# ./merge_into_monorepo.sh https://github.com/old-org/old-repo.git https://github.com/new-org/monorepo.git old-repo
# Define the input variables.
REPOSITORY_TO_ABSORB_FROM=$1
REPOSITORY_TO_ABSORB_INTO=$2
PATH_IN_MONOREPOSITORY=$3
# Temporary branch name and directory.
TEMPORARY_BRANCH_NAME=prepare_monorepo
TEMPORARY_DIR=temp_dir
# Function to clean up the temporary directory.
clean_up() {
echo "Cleaning up temporary directory..."
rm -Rf $TEMPORARY_DIR
}
# Check if temporary directory exists, if so, delete it.
if [ -d "$TEMPORARY_DIR" ]
then
echo "Temp dir already exists, deleting it.."
clean_up
fi
# Create the necessary directories.
mkdir -p "$TEMPORARY_DIR/oldRepo"
mkdir -p "$TEMPORARY_DIR/monoRepo"
# Clone the repositories into temporary directories.
git clone $REPOSITORY_TO_ABSORB_FROM $TEMPORARY_DIR/oldRepo
git clone $REPOSITORY_TO_ABSORB_INTO $TEMPORARY_DIR/monoRepo
# Switch to the old repository directory and prepare it for merging.
cd $TEMPORARY_DIR/oldRepo
git checkout -b "$TEMPORARY_BRANCH_NAME"
mkdir -p $PATH_IN_MONOREPOSITORY
# Enable extended globbing for moving everything except for the monorepo path.
shopt -s extglob
shopt -s dotglob
git mv -k !($PATH_IN_MONOREPOSITORY) $PATH_IN_MONOREPOSITORY
# Remove unneeded files.
git rm -f --ignore-unmatch .gitattributes
git rm -f --ignore-unmatch .editorconfig
git commit -m "Preparing $PATH_IN_MONOREPOSITORY for monorepo $TEMPORARY_DIR"
# Switch to the monorepo and prepare it for merging.
cd ../monoRepo/
git checkout -b $TEMPORARY_BRANCH_NAME
# Check if the submodule exists, if so, delete it.
if [ -d "$PATH_IN_MONOREPOSITORY" ]
then
git rm -f $PATH_IN_MONOREPOSITORY
git commit -m "Preparing $PATH_IN_MONOREPOSITORY for monorepo $TEMPORARY_DIR, removing old git submodule"
fi
# Add the old repository as a remote and merge it.
OLD_REPO_NAME=$(basename $REPOSITORY_TO_ABSORB_FROM)
git remote add -f $OLD_REPO_NAME ../oldRepo
git merge -m "Preparing $PATH_IN_MONOREPOSITORY for monorepo $TEMPORARY_DIR, Integrating $OLD_REPO_NAME" $OLD_REPO_NAME/$TEMPORARY_BRANCH_NAME --allow-unrelated-histories
# Push the changes to the monorepo.
git push -f --set-upstream origin $TEMPORARY_BRANCH_NAME
# Clean up temporary directory.
clean_up
# Exit the script.
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment