Some time ago we needed to create a new product that shares many features with the existing one. The first idea was to extract some of the code into a library, to be then imported and used independently in the two projects.
After creating the repository for the library, the first thing I would have done was copy the files from one repo to another. Well, it works like a charm, it’s fast, and it doesn’t require any particular expertise — a normal drag-and-drop operation. What’s more? It could be a very effective approach, but …
During a PR review, I learnt there was a clever way to perform this operation, and I wasn’t even aware such a thing was possible before:
Moving files from one git repository to another retaining the history.
Moving a single directory#
From the source repository:
git clone <src_repository> <src_repository>_clone
# clone the src repository in new foldercd <src_repository>_clonegit remote rm origin
# remove the origin to avoid disasters in case of errorgit filter-branch --subdirectory-filter <directory> -- --all
# the magic, rewrite the git historymkdir <directory>
mv * <directory>
# create the directory and move everything insideIn the destination repository:
git remote add <src_repository> <git repository A directory>
# clone the repository, if not previously donegit pull repo-A master --allow-unrelated-histories
# Import the src repository code into the dst repositorygit mv <directory_1> <desired_position>
# Optionally, move the just imported files, into the desired position in the new repositoryMoving code file-by-file#
The operations required to move many files at once are conceptually the same. The extraction of the files to be moved will be performed by means of the following script (from Tom Hacohen’s blog article):
After changing the script to include the files to be imported, it must be executed just before the git filter-branch ... command; this will create a single folder in the repository. So, to recap:
Download the script, and change it according to the files to be copied.
From the source repository:
git clone <src_repository> <src_repository>_clone
# clone the src repository in new foldercd <src_repository>_clonegit remote rm origin
# remove the origin to avoid disasters in case of errorExecute the script previously modified here, so assuming the script has been saved in the parent folder:
bash $(pwd)/../git-move.shAt this point, the repository contains only the folder and the files specified in the script.
git filter-branch --subdirectory-filter <directory> -- --all
# the magic, rewrite the git historymkdir <directory>
mv * <directory>
# create the directory and move everything insideIn the destination repository:
git remote add <src_repository> <git repository A directory>
# clone the repository, if not previously donegit pull repo-A master --allow-unrelated-histories
# Import the src repository code into the dst repositorygit mv <directory_1> <desired_position>
# Optionally, move the just imported files, into the desired position in the new repositoryConclusions#
That easy? Yep. Despite the many commands to be run, the advantage of maintaining the history is priceless — especially when we need to investigate some issue, file history can be very useful.
Tip: The process could seem counterintuitive, so I suggest giving it a try with a test repository. After the first time, everything will be much clearer.
