Skip to content

Instantly share code, notes, and snippets.

@jdpaton
Created August 27, 2013 20:49
Show Gist options
  • Save jdpaton/6358983 to your computer and use it in GitHub Desktop.
Save jdpaton/6358983 to your computer and use it in GitHub Desktop.
This script splits a subfolder of an existing git repo into its own separate repo. It will preserve all tags by default, and any branches specified with '-b'. Usage example: ./git-split-subfolder.sh -p git://repo.com/foo -services -s mysubfolder -b "branch1 branch2 branch3" The new repo 'mysubfolder' will be in the $CWD.
#!/bin/bash
set -e
usage() {
cat << EOF
usage: $0 [options]
This script splits an existing folder inside of a git repo into its own
separate git repo, optionally preserving all existing tags and branches from the
parent repo.
OPTIONS:
-h Show this message
-p URI / Path to parent repo
-s Subfolder name
-b List of any branches to preserve i.e '-b "branch1 branch2 branch3"'
-c Don't run any pruning or gc on the new repo
-t Don't bring over existing branches and tags
EOF
}
PARENT_REPO_URI=
SUBFOLDER_NAME=
PRESERVE_BRANCHES=
NO_CLEANUP=
TAGS_AND_BRANCHES="-- --all"
while getopts “hs:p:b:c:t:” OPTION
do
case $OPTION in
h)
usage
exit 1
;;
p)
PARENT_REPO_URI=$OPTARG
;;
s)
SUBFOLDER_NAME=$OPTARG
;;
b)
PRESERVE_BRANCHES=$OPTARG
;;
c)
NO_CLEANUP=true
;;
t)
TAGS_AND_BRANCHES=""
;;
?)
usage
exit
;;
esac
done
if [ -z "${PARENT_REPO_URI}" ] || [ -z "${SUBFOLDER_NAME}" ];
then
usage
exit 1
fi
function cleanup {
header "Performing GC on the new repo"
git reset --hard
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --aggressive --prune=now
}
function header {
echo "---- $1 ----"
}
header "Cloning existing repo at ${PARENT_REPO_URI}"
git clone $PARENT_REPO_URI $SUBFOLDER_NAME
pushd $SUBFOLDER_NAME
if [[ "${PRESERVE_BRANCHES}" ]] && [[ "${TAGS_AND_BRANCHES}" ]]
then
header "Setting up tracking for existing branches"
pushd $SUBFOLDER_NAME
for branch in $PRESERVE_BRANCHES
do
git branch -t $branch origin/$branch
done
popd
fi
header "Removing existing remote origin"
git remote remove origin
header "Filtering the branch"
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter $SUBFOLDER_NAME $TAGS_AND_BRANCHES
if [ -z "$NO_CLEANUP" ]
then
cleanup
fi
header "Done!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment