|
#!/bin/bash |
|
set -euo pipefail |
|
|
|
# --- Configuration --- |
|
# Get the absolute path of the script's location. |
|
REPO_DIR=$(pwd) |
|
# List of repository directories to merge, separated by spaces. |
|
REPOS="frontend backend" |
|
# The name of the main branch in the source repositories. |
|
MAIN="release" |
|
# The name of the final merged directory. |
|
MERGED_DIR="merged" |
|
|
|
# --- Setup --- |
|
# Add current directory to PATH if git-filter-repo is present locally. |
|
# This allows the script to find the tool without a system-wide installation. |
|
if [ -x "./git-filter-repo" ]; then |
|
export PATH="$(pwd):$PATH" |
|
fi |
|
|
|
# --- Sanity Checks --- |
|
# Check if git-filter-repo is available. |
|
if ! command -v git-filter-repo &> /dev/null; then |
|
echo "Error: git-filter-repo could not be found." >&2 |
|
echo "Please install it or place the executable in the current directory." >&2 |
|
exit 1 |
|
fi |
|
|
|
# Check if the specified repository directories exist. |
|
for repo in $REPOS; do |
|
if [ ! -d "$repo/.git" ]; then |
|
echo "Error: Directory '$repo' does not exist or is not a git repository." >&2 |
|
exit 1 |
|
fi |
|
done |
|
|
|
echo "✅ All checks passed. Starting merge process..." |
|
|
|
# --- Step 1: Rewrite history for each repo into a temporary location --- |
|
# We use a temporary directory to avoid modifying the original repositories. |
|
# The '$$' appends the process ID to make the directory name unique. |
|
TEMP_DIR="/tmp/git-merge-repos-$$" |
|
|
|
# Set up a trap to automatically clean up the temporary directory on script exit, |
|
# regardless of whether it succeeds, fails, or is interrupted (e.g., by Ctrl+C). |
|
trap 'echo "Exiting. Cleaning up temporary directory..." >&2; rm -rf "$TEMP_DIR"' EXIT |
|
|
|
echo "Creating temporary directory at $TEMP_DIR" |
|
mkdir -p "$TEMP_DIR" |
|
|
|
for repo in $REPOS; do |
|
echo "--------------------------------------------------" |
|
echo "Processing: $repo" |
|
echo "--------------------------------------------------" |
|
|
|
# Create a fresh, clean clone in the temp directory to work on. |
|
# Using file:// ensures it works correctly with local paths. |
|
echo "Cloning '$repo' to a temporary location..." |
|
git clone "file://$REPO_DIR/$repo" "$TEMP_DIR/$repo" |
|
|
|
cd "$TEMP_DIR/$repo" |
|
|
|
# Rewrite the history of the clone using the much improved method. |
|
echo "Rewriting history for '$repo'..." |
|
git-filter-repo \ |
|
--to-subdirectory-filter "$repo" \ |
|
--message-callback "return message" \ |
|
--commit-callback "commit.committer_date = commit.author_date" \ |
|
--force |
|
|
|
echo "Finished processing '$repo'." |
|
done |
|
|
|
# --- Step 2: Create the new merged repository --- |
|
echo "--------------------------------------------------" |
|
echo "Creating the final '$MERGED_DIR' repository" |
|
echo "--------------------------------------------------" |
|
cd "$REPO_DIR" |
|
# Clean up the target directory from any previous run before we start. |
|
rm -rf "$MERGED_DIR" |
|
mkdir "$MERGED_DIR" |
|
cd "$MERGED_DIR" |
|
# Initialize the repository with a modern default branch name. |
|
git init -b main |
|
|
|
# --- Step 3: Merge all the rewritten repositories --- |
|
for repo in $REPOS; do |
|
echo "Merging history from '$repo'..." |
|
|
|
# Add the rewritten repo from our temp directory as a remote. |
|
git remote add "$repo" "$TEMP_DIR/$repo" |
|
|
|
# Fetch its content. |
|
git fetch "$repo" |
|
|
|
# Merge its main branch into our new history. |
|
# --allow-unrelated-histories is essential because the repos |
|
# do not share a common root commit. |
|
# We create a clear merge commit message to document the action. |
|
git merge "$repo/$MAIN" --allow-unrelated-histories -m "feat: Merge repository '$repo'" |
|
|
|
# Clean up by removing the remote connection. |
|
git remote remove "$repo" |
|
done |
|
|
|
# --- Step 4: Final Cleanup --- |
|
# The temporary directory ($TEMP_DIR) is removed automatically by the 'trap' |
|
# we set at the beginning of the script. This ensures cleanup happens |
|
# even if the script fails partway through. |
|
|
|
echo "--------------------------------------------------" |
|
echo "✅ Success!" |
|
echo "The merged repository is now available in the '$MERGED_DIR' directory." |
|
echo "Run 'cd $MERGED_DIR && git log --oneline --graph' to inspect the new history." |