epcim
4/12/2017 - 11:51 AM

Move a subdirectory from one git repository to a subdirectory of another, without losing commit history.

Move a subdirectory from one git repository to a subdirectory of another, without losing commit history.

# Assumptions:
#
# * After the merge is complete, the directory should exist in the target repository and not exist in the source
#   repository. In other words, this is a move, not a cross-reference: we never want to be able to push commits
#   back to the source repository, or merge further changes from the source repository. If you want to do that
#   instead, a subtree merge is what you're looking for.
#
# * The directory doesn't exist in the target repository yet.
#
# In this example, we're moving the "/openstack-swift/" directory from jclouds/jclouds-labs-openstack to
# "/apis/openstack-swift/" in jclouds/jclouds.

# Get a clone of the target repository.
git clone git@github.com:jclouds/jclouds.git
cd jclouds

# Add the source repository as a remote, and perform the initial fetch.
git remote add -f sourcerepo git@github.com:jclouds/jclouds-labs-openstack.git

# Create a branch based on the source repositories' branch that contains the state you want to copy.
git checkout -b staging-branch sourcerepo/master

# Delete everything that isn't the directory we want to move.
# Don't worry, we're not going to push this back ;-)
git rm -r openstack-glance/ openstack-heat/ openstack-marconi/ \
  openstack-neutron/ openstack-autoscale/ rackspace-* \
  *.md pom.xml
git commit -m "Delete everything we don't want to merge"

# Move the directory into its final position.
mkdir apis/
git mv openstack-swift/ apis/
git commit -m "Lock S-foils in attack position"

# Change back to master and merge it in.
# You could also do this by submitting a pull request, of course. I had one conflict, in /.mailmap.
git checkout master
git merge staging-branch

# I had one conflict, in /.mailmap. Fix it, stage it, and commit it to finalize the merge.
${EDITOR} .mailmap
git add .mailmap
git commit

# Voila! The directory has moved, and you still have full history:
#
#  ~/samples/jclouds (master>) $ git log --follow --oneline apis/openstack-swift/pom.xml
#  cb930d9 Move openstack-swift into apis/.
#  491dc97 Revert "Fix poms so that modernizer doesn't fail on snapshot."
#  889243a Fix poms so that modernizer doesn't fail on snapshot.
#  d65048d Fix Maven parent.relativePath warnings
#  f33e90e Updating project versions to 2.0.0-SNAPSHOT
#  be8bc22 Up to 2.0.0-SNAPSHOT after the 1.8.0 release
#
# (Notice that you do need the --follow to trace through the git mv I did.)

# Next: be sure to promptly delete the directory from the source repository by normal means
# (git rm -r dir/ && git commit && git push && pull request), because you don't have an
# easy way to update the target repository with further changes.