Patrick Ward words, code, and music

Merge Two Git Repos Into One

I needed to merge two distinct git repositories into a single parent repository as subdirectories the other day. I wanted to remove the separate repositories and add them as subdirectories within the parent repo, all while retaining the original repo history.

After a little trial and error, I found the following worked well for me.

Within the following code examples, I’m using widgets as the new, merged repository and widget1 as an older repository to be merged in.

First, create the new parent repo and send it up to Github or Bitbucket:

  mkdir widgets
  cd widgets
  git init
  git remote add origin git@servername:username/widget1.git
  vim README.md
  git add .
  git commit -m "Initial commit for merged repo"
  git push -u origin master

Simple enough. Next, I created a clone of each repo I wanted to merge and ran filter-branch on them to ensure that each repo looked as if it had always been developed within it’s own directory.

  git clone widget1 widget1_copy
  cd widget1_copy

  # This moves all files into a new widget1 directory
  git filter-branch --prune-empty --tree-filter '
  if [[ ! -e widget1 ]]; then
    mkdir -p widget1
    git ls-tree --name-only $GIT_COMMIT \
    | xargs -I files mv files widget1
  fi'

The above procedure was run for each repository I wanted to merge into the widgets repository.

Finally, I merged each of the filtered repos into the new parent repo.

  cd widgets
  git remote add -f widget1 ../widget1_copy
  git merge -s ours --no-commit widget1/master
  git read-tree --prefix=/ -u widget1/master
  git commit -m "Merged widget1"

  # Once last check to make sure we have everything
  git pull -s subtree widget1 master

  # Finally, remote the remote and push
  git remote remove widget1
  git push

Again, the above procedure was run for each sub-repo I was merging in to the new repository.

The final result is that I have a single repository with each of the older repositories as a subdirectory of the new repo, along with the previous repository history in tact.