Pages - Menu

Git - Moving Code between Repositories Changing Commit History


As part of our microservices migration, we recently did a lot of code moving and splitting from one monolithic repository into multiple smaller repositories.

Perhaps it is easier to just copy and paste files and done with, but if we want to retain the commit history as we move, then it will take a little extra efforts.


Create New Repository

Firstly, we need to create a new repository. We could do that in Azure DevOps.

Move a subfolder (with commit history) to a different repository

Preparing local folders
# Clone the old repo locally.
$ mkdir new_repo_folder
$ cd new_repo_folder
$ git clone old_repo_url
$ cd old_repo_folder

Filter out by subfolder
# If you are moving subfolder of subfolder, we need to use slash as a path delimiter even in Windows.
$ git filter-branch --subdirectory-filter another_subfolder_if_any/subfolder_to_move -- --all
$ git remote -v                                                    
$ git remote set-url origin new_repo_url                      
$ git remote -v                                                    
$ git push origin

At this point, this is now completed. All the codes in the subfolder are moved to the new repository with all the history. However the new repository will have a local path new_repo_folder/old_repo_folder/code. If we want it to look like new_repo_folder/code, we can just clean it up by copy and paste.


As we were trying out and moving codes around, I have also encountered some rare scenarios and learnt some 'rarely' needed commands.

Cherry pick commits from another repository to a subfolder locally

# go to dest folder
$ git clone dest_repo_url
$ cd dest
$ git checkout dest-branch
$ git checkout -b merge-src-to-dest

# add the copy source repo as new remote
$ git remote add src src_repo_url
$ git remote -v
$ git fetch src

# Specify remote name when cherry pick, and supply subtree parameter to apply to subfolder
# tip of the branch
$ git cherry-pick -Xsubtree="subfolders/more-subfolder" src/remote-branch-name

# 4th commit from the branch
$ git cherry-pick -Xsubtree="subfolders/more-subfolder" src/remote-branch-name~4

# commit hash don't require remote-branch-name, but src must be fetched
$ git cherry-pick -n -Xsubtree="subfolders/more-subfolder" commit-hash

# git cherry pick of a merge (eg. merged pull request)
$ git cherry-pick -Xsubtree="subfolders/more-subfolder" src/remote-branch-name -m 1

# clean up
$ git remote rm src

Other Commands

# Rename a remote branch name
$ git branch -m old_branch new_branch
$ git push origin new_branch

# but we still point to the remote old_branch in .git
[branch "new_branch"]
 remote = origin
 merge = refs/heads/old_branch

# Create 'new_branch' and set up track remote at the same time.
$ git push origin -u new_branch

# git push to a different remote branch
$ git push origin src-branch:target-branch
$ git push origin branch1:branch2