Skip to content

Instantly share code, notes, and snippets.

@npryce
Last active February 22, 2024 17:23
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save npryce/4380394 to your computer and use it in GitHub Desktop.
Save npryce/4380394 to your computer and use it in GitHub Desktop.
Merge history from one Git repository as the history of a subdirectory of another Git repository
#!/bin/bash
# Usage: merge-to-subdir source-repo destination-repo subdir
#
# Merges the history of source-repo into destination-repo as the
# history of the subdirectory subdir.
#
# source-repo can be local or remote.
# destination-repo must be local to the machine.
# subdir can be a relative path, in which case intermediate
# directories are created as necessary.
#
# WARNING: I've only tested it when subdir has not existed within destination-repo.
set -e
function abspath() {
(cd $(dirname $1) && echo $PWD/$(basename $1))
}
from=${1:?from repo not given}
to=$(abspath ${2:?to repo not given})
subdir=${3:?subdir not given}
scratch=$(abspath $(basename $from .git)-scratch)
# Use the name of the subdirectory as the name of the remote when merging
remote=tmp-$subdir
# Create a copy of $from with contents moved to $subdir
rm -rf $scratch
git clone $from $scratch
cd $scratch
git filter-branch -f --prune-empty --tree-filter "
mkdir -p .tmp
mv * .tmp
if [ -f .gitignore ]; then mv .gitignore .tmp; fi
mkdir -p $(dirname $subdir)
mv .tmp $subdir
" -- --all
git gc --aggressive
cd ..
# Merge the copy of $from into $to
cd $to
git remote add $remote $scratch
git fetch $remote
git merge $remote/master
git remote rm $remote
git gc --aggressive
cd ..
# Clean up
rm -rf $scratch
@diogobaeder
Copy link

Nice, man! It would be even neater if you put some comments on how to use it, though :-)

@npryce
Copy link
Author

npryce commented Dec 27, 2012

Usage: merge-to-subdir source-repo destination-repo subdir

Merges the history of source-repo into destination-repo as the history of the subdirectory subdir.

source-repo can be local or remote.
destination-repo must be local to the machine.
subdir can be a relative path, in which case intermediate directories are created as necessary.

I've only tested it when subdir has not existed within destination-repo.

@graearea
Copy link

graearea commented Jan 3, 2023

I cant edit or raise a PR. can you add:
# assumes trunk is named master. change to main as required
and change the merge line to ->
git merge $remote/main --allow-unrelated-histories

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment