Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git move directory to another repository while keeping the history

Tags:

git

First - apologies for asking this question. There are a lot of topics about it already. But I'm not having much luck with them. My lack of familiarity with git is not much help.

I'm moving a folder from one git repo to another (which already exists). e.g.

repo-1 ---- dir1 ---- dir2 ---- dir3 ---- dir-to-move ---- dir5  repo-2 ---- dir1 ---- dir2 ---- dir3 

In the end I want the repos to look like

repo-1 ---- dir1 ---- dir2 ---- dir3 ---- dir-to-move ---- dir5  repo-2 ---- dir1 ---- dir2 ---- dir3 ---- dir-to-move 

i.e. For a time dir-to-move will exist in both repos. But eventually I'll migrate the latest changes to repo-2 and remove dir-to-move from repo-1.

My initial research made me believe that I needed to use filter-branch. e.g.

How to move files from one git repo to another preserving history using `git format-patch`and `git am`

I've since learnt that subtree superseded that approach. However it's not doing what I expected. I thought I'd be able to do something like

In repo-1 workspace

git subtree split -P dir-to-move -b split 

to filter the split branch down to only dir-to-move and it's history. Then in repo-2 workspace

git remote add repo-1 repo-1-url.git git subtree add --prefix dir-to-move split 

This does move the code across. It also, sort of, includes the history

e.g.

cd repo-2 git log 

Shows commits from repo-1

but

cd repo-2 git log dir-to-move 

Shows only an 'Add dir-to-move from commit ....'

i.e. The history is included but does not show up when checked for the specific files/directories.

How can I do this properly?

like image 945
Shane Gannon Avatar asked Jan 23 '17 17:01

Shane Gannon


People also ask

How do I merge git repositories and keep history?

To combine two separate Git repositories into one, add the repository to merge in as a remote to the repository to merge into. Then, combine their histories by merging while using the --allow-unrelated-histories command line option.


2 Answers

I can't help you with git subtree, but with filter-branch it's possible.

First you need to create a common repository that will contain both source and destination branches. This can be done by adding a new "remote" beside "origin" and fetching from the new remote.

Use filter-branch on the source branch to rm -rf all directories except dir-to-move. After that you'll have a commit history that can be cleanly rebased or merged into the destination branch. I think the easiest way is to cherry-pick all non-empty commits from the source branch. The list of these commits can be obtained by running git rev-list --reverse source-branch -- dir-to-move

Of course, if the history of dir-to-move is non-linear (already contains merge commits), then it won't be preserved by cherry-pick, so git merge can be used instead.

Example create common repo:

cd repo-2 git remote add source ../repo-1 git fetch source 

Example filter branch

cd repo-2 git checkout -b source-master source/master CMD="rm -rf dir1 dir2 dir3 dir5" git filter-branch --tree-filter "$CMD" 

Example cherry-pick into destination master

cd repo-2 git checkout master git cherry-pick `git rev-list --reverse source-master -- dir-to-move` 
like image 110
basin Avatar answered Oct 06 '22 21:10

basin


FWIW, the following worked for me after a number of iterations.

Clone both the repos to a temporary work area.

git clone <repourl>/repo-1.git  git clone <repourl>/repo-2.git cd repo-1 git remote rm origin # delete link to original repository to avoid any accidental remote changes git filter-branch --subdirectory-filter dir-to-move -- --all  # dir-to-move is being moved to another repo.  This command goes through history and files, removing anything that is not in the folder.  The content of this folder will be moved to root of the repo as a result.  # This folder has to be moved to another folder in the target repo.  So, move everything to another folder. git filter-branch -f --index-filter \ 'git ls-files -s | /usr/local/bin/sed -e "s/\t\"*/&dir-to-move\//" |     GIT_INDEX_FILE=$GIT_INDEX_FILE.new \         git update-index --index-info &&  mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD # Above command will go through history and rewrite the history by adding dir-to-move/ to each files.  As a result, all files will be moved to a subfolder /dir-to-move.  Make sure to use gnu-sed as OSX sed doesn't handle some extensions correctly.  For eg. \t 

Now switch to target repo and fetch everything from source.

git clone repo-2 git remote add master ../repo-1/ git pull master master --allow-unrelated-histories git push  # push everything to remote  

Above steps assume that master branches are used for both source and targets. However, tags and branches were ignored.

like image 38
donnie Avatar answered Oct 06 '22 22:10

donnie