Nick
Nick

Reputation: 1008

Merging Git Repositories

I have two repositories that I would like to merge. Lets call them old-style and new-style. My team stopped using old-style December 31, 2016 and began using new-style January 1, 2017. The directory/project style was copied over from old-style and moved to new-style except the history. I would like to merge these two history's together so I can see what has changed in the project.

How would I do this? A lot of blogs suggest taking old-style and making it a child directory of new-style and then merging their unrelated histories. But I believe my histories are related. Doing this would make it appear that the code bases were not similar.

old-style: c1--c2--c3--c4--c5 <- master
January 1 2017  
new-style: c1--c2--c3--c4--c5--c6-- <- master

If I make old-style a child directory of new-style I would have to have a commit indicating that a merge happened at some point.

old-style: c1--c2--c3--c4--c5 <- master
             January 1 2017  \
                   new-style: c1'--c2'--c3'--c4'--c5'--c6'--c7 <- master
message at c7 indicating that old-style was added to new-style

What the ideal output would be

c1--c2--c3--c4--c5--c1'--c2'--c3'--c4'--c5'--c6'--c7-- <- master

Upvotes: 3

Views: 121

Answers (2)

Nick
Nick

Reputation: 1008

I found a solution that worked for me. This all needs to be done in GitBash and not in Powershell.

You will need to know the first commit hash of your new style repository and your last commit hash of your old style repository.

In your new-style clone run

git rev-list --max-parents=0 HEAD

Output

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

In your old-style clone run

git rev-parse HEAD

Output

de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3

Clone the new-style repository

git clone https://GitWebsite.repos/new-style.git
cd new-style

Add the old-style repository as a remote

git remote add history https://GitWebsite.repos/old-style.git
git fetch history

Now to convert the branch I am going to use git-filter-branch. I understand this to work in a way similar to how TFVC works. You're taking a snapshot of the commit and moving forward and not working with the diffs between commits. Git will not try to do any resolution between the two commits. It reminds me of the Wallace and Gromit movie "The Wrong Trousers" during the train chase scene Grommit is placing trackdown in front of the train as it is moving forward.

git filter-branch --parent-filter 'test $GIT_COMMIT = 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12 && echo "-p de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3" || cat' HEAD

Now many hours later that is done. You can force push this repository up to your git host.

git push -f

You should see the code in a single linear history now.

A lot of thanks to this answer https://stackoverflow.com/a/44078243/2375884

Upvotes: 1

bk2204
bk2204

Reputation: 77034

Your ideal situation graph describes a rebase, which you can do. If you have these two repositories as branches, you can run git rebase --root --onto old-style new-style, which will produce a linear history.

You may also want to use --rebase-merges if new-style is a main development branch that uses a typical merging workflow to preserve the merge commits instead of omitting them. This requires a reasonably recent Git version.

If you really want to use a merge, you'll need to merge with --allow-unrelated-histories, since the branches, while sharing code, don't share an actual common commit.

Upvotes: 1

Related Questions