#!/bin/bash # ################################################################################ ## Script to merge multiple git repositories into a new repository ## - The new repository will contain a folder for every merged repository ## - The script adds remotes for every project and then merges in every branch ## and tag. These are renamed to have the origin project name as a prefix ## ## Usage: mergeGitRepositories.sh <new_project> <my_repo_urls.lst> ## - where <new_project> is the name of the new project to create ## - and <my_repo_urls.lst> is a file contaning the URLs to the respositories ## which are to be merged on separate lines. ## ## Author: Robert von Burg ## [email protected] ## ## Version: 0.3.2 ## Created: 2018-02-05 ## ################################################################################ #
# disallow using undefined variables shopt -s -o nounset
functioncommit_merge() { current_branch="$(git symbolic-ref HEAD 2>/dev/null)" if [[ ! -f ".git/MERGE_HEAD" ]] ; then echo -e "INFO: No commit required." echo -e "INFO: No commit required." >>${LOG_FILE} 2>&1 else echo -e "INFO: Committing ${sub_project}..." echo -e "INFO: Committing ${sub_project}..." >>${LOG_FILE} 2>&1 if ! git commit -m "[Project] Merged branch '$1' of ${sub_project}" >>${LOG_FILE} 2>&1 ; then failed "Failed to commit merge of branch '$1' of ${sub_project} into ${current_branch}" fi fi }
# Make sure the REPO_URL_FILE exists if [ ! -e "${REPO_URL_FILE}" ] ; then echo -e "ERROR: Repo file ${REPO_URL_FILE} does not exist!" exit 1 fi
# Make sure the required directories don't exist if [ -e "${PROJECT_PATH}" ] ; then echo -e "ERROR: Project ${PROJECT_NAME} already exists!" exit 1 fi
# create the new project echo -e "INFO: Logging to ${LOG_FILE}" echo -e "INFO: Creating new git repository ${PROJECT_NAME}..." echo -e "INFO: Creating new git repository ${PROJECT_NAME}..." >>${LOG_FILE} 2>&1 echo -e "====================================================" echo -e "====================================================" >>${LOG_FILE} 2>&1 cd${ROOT_DIR} mkdir${PROJECT_NAME} cd${PROJECT_NAME} git init echo"Initial Commit" > initial_commit # Since this is a new repository we need to have at least one commit # thus were we create temporary file, but we delete it again. # Deleting it guarantees we don't have conflicts later when merging git add initial_commit git commit --quiet -m "[Project] Initial Master Repo Commit" git rm --quiet initial_commit git commit --quiet -m "[Project] Initial Master Repo Commit" echo
# Merge all projects into the branches of this project echo -e "INFO: Merging projects into new repository..." echo -e "INFO: Merging projects into new repository..." >>${LOG_FILE} 2>&1 echo -e "====================================================" echo -e "====================================================" >>${LOG_FILE} 2>&1 for url in $(cat${REPO_URL_FILE}) ; do
if [[ "${url:0:1}" == '#' ]] ; then continue fi
# extract the name of this project export sub_project=${url##*/} sub_project=${sub_project%*.git}
# create and checkout new merge branch off of master if ! git checkout -b "${sub_project}/${branch_name}" master >>${LOG_FILE} 2>&1 ; then failed "Failed preparing ${branch_name}" ; fi if ! git reset --hard ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi if ! git clean -d --force ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi
# Merge the project echo -e "INFO: Merging ${sub_project}..." echo -e "INFO: Merging ${sub_project}..." >>${LOG_FILE} 2>&1 if ! git merge --allow-unrelated-histories --no-commit "remotes/${sub_project}/${branch_name}" >>${LOG_FILE} 2>&1 ; then failed "Failed to merge branch 'remotes/${sub_project}/${branch_name}' from ${sub_project}" fi
# And now see if we need to commit (maybe there was a merge) commit_merge "${sub_project}/${branch_name}"
# relocate projects files into own directory if [ "$(ls)" == "${sub_project}" ] ; then echo -e "WARN: Not moving files in branch ${branch_name} of ${sub_project} as already only one root level." echo -e "WARN: Not moving files in branch ${branch_name} of ${sub_project} as already only one root level." >>${LOG_FILE} 2>&1 else echo -e "INFO: Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..." echo -e "INFO: Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..." >>${LOG_FILE} 2>&1 mkdir${sub_project} for f in $(ls -a) ; do if [[ "$f" == "${sub_project}" ]] || [[ "$f" == "." ]] || [[ "$f" == ".." ]] ; then continue fi git mv -k "$f""${sub_project}/" done
# commit the moving if ! git commit --quiet -m "[Project] Move ${sub_project} files into sub directory" ; then failed "Failed to commit moving of ${sub_project} files into sub directory" fi fi echo done < <(git ls-remote --heads ${sub_project})
# checkout master of sub probject if ! git checkout "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then failed "sub_project ${sub_project} is missing master branch!" fi
# hack for broken tag names where they are like 1.2.0^{} instead of just 1.2.0 tag_name="${tag_name_unfixed%%^*}"
tag_new_name="${sub_project}/${tag_name}" echo -e "INFO: Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..." echo -e "INFO: Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..." >>${LOG_FILE} 2>&1 if ! git tag "${tag_new_name}""${tag_ref}" >>${LOG_FILE} 2>&1 ; then echo -e "WARN: Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}" echo -e "WARN: Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}" >>${LOG_FILE} 2>&1 fi done < <(git ls-remote --tags --refs ${sub_project})
# Remove the remote to the old project echo -e "INFO: Removing remote ${sub_project}..." echo -e "INFO: Removing remote ${sub_project}..." >>${LOG_FILE} 2>&1 git remote rm${sub_project}
echo done
# Now merge all project master branches into new master git checkout --quiet master echo -e "INFO: Merging projects master branches into new repository..." echo -e "INFO: Merging projects master branches into new repository..." >>${LOG_FILE} 2>&1 echo -e "====================================================" echo -e "====================================================" >>${LOG_FILE} 2>&1 for url in $(cat${REPO_URL_FILE}) ; do
if [[ ${url:0:1} == '#' ]] ; then continue fi
# extract the name of this project export sub_project=${url##*/} sub_project=${sub_project%*.git}
echo -e "INFO: Merging ${sub_project}..." echo -e "INFO: Merging ${sub_project}..." >>${LOG_FILE} 2>&1 if ! git merge --allow-unrelated-histories --no-commit "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then failed "Failed to merge branch ${sub_project}/master into master" fi
# And now see if we need to commit (maybe there was a merge) commit_merge "${sub_project}/master"