Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
# We need the TAB character for SED (Mac OS X sed does not understand \t)
TAB="$(printf '\t')"
function abort {
echo "$(tput setaf 1)$1$(tput sgr0)"
exit 1
function request_input {
read -p "$(tput setaf 4)$1 $(tput sgr0)"
function request_confirmation {
read -p "$(tput setaf 4)$1 (y/n) $(tput sgr0)"
[ "$REPLY" == "y" ] || abort "Aborted!"
cat << "EOF"
This script rewrites your entire history, moving the current repository root
into a subdirectory. This can be useful if you want to merge a submodule into
its parent repository.
For example, your main repository might contain a submodule at the path src/lib/,
containing a file called "test.c".
If you would merge the submodule into the parent repository without further
modification, all the commits to "test.c" will have the path "/test.c", whereas
the file now actually lives in "src/lib/test.c".
If you rewrite your history using this script, adding "src/lib/" to the path
and the merging into the parent repository, all paths will be correct.
NOTE: This script might complete garble your repository, so PLEASE apply this
only to a clone of the repository where it does not matter if the repo is destroyed.
request_confirmation "Do you want to proceed?"
cat << "EOF"
Please provide the path which should be prepended to the current root. In the
above example, that would be "src/lib". Please note that the path MUST NOT contain
a trailing slash.
request_input "Please provide the desired path (e.g. 'src/lib'):"
# Escape input for SED, taken from
TARGET_PATH=$(echo -n "$REPLY" | sed -e 's/[\/&]/\\&/g')
# Last confirmation
git ls-files -s | sed "s/${TAB}/${TAB}$TARGET_PATH\//"
request_confirmation "Please take a look at the printed file list. Does it look correct?"
# The actual processing happens here
CMD="git ls-files -s | sed \"s/${TAB}/${TAB}$TARGET_PATH\//\" | GIT_INDEX_FILE=\${GIT_INDEX_FILE}.new git update-index --index-info && mv \${GIT_INDEX_FILE}.new \${GIT_INDEX_FILE}"
git filter-branch \
--index-filter "$CMD" \

This is awesome. Thank you! Also note that in your main article related to this, the syntax for the following command has changed:

$ git merge -s ours --no-commit sub/master


$ git merge -s ours --no-commit --allow-unrelated-histories sub/master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment