Stefan Hoth
Stefan Hoth

Reputation: 2685

Bringing two different git repositories together without losing either history

In my current project I am facing an interesting problem with git:

Since the beginning of the project changes were stored in a SVN repository on a remote server at my client. In the progress of development I started to have a local git repository in parallel to make it easier for me to test new features without breaking the current version. Sadly git-svn failed to work which would have make my life easier.

Now my client switch to another server and in this process they moved the SVN repo to git (using git2svn).

Although I'm happy about this in general, I have two problems now:

  1. Since I worked on a bigger feature I didn't commit to SVN for 7 days. I worked in a local feature branch and made backups of that to my local server but the SVN copy which is now the remote git repo is outdated compared to my local version.

  2. Since the remote repo has been created by git2svn it is totally different from my own repo (message: Warning: Repo has no common commits.) - which makes standard merging impossible.

Now my desired goals:

  1. Merge both repos to have my current version be the checked in one and push to origin works again.

  2. Keep the history of both repos (old ones from SVN as well as the ones from the last 7 days from my git)

What I tried so far:

I tried to clone the remote git (from svn) and merged my local repo into it. I got 153 conflicts with "changed in both versions". Accepting "theirs" (i.e. my latest developments) loses the history of the file (it just starts with the initialisation with my parallel git repo).

My idea is that I can create a patch for each commit of the last 7 days and commit this into the new repo with the corresponding commit message (i.e. "manual merge"). Before I write a script to do this, I wanted to ask if there is a built-in way to do that.

Thanks in advance!

UPDATE: I tried many solutions but every one of them failed me. The basic problem is that I have two branches now with not a single common commit but the same tree structure. This results in merge conflicts like "added in both branches" because git doesn't know that myFile.txt" andmyFile.txt" are the same and can be merged. Instead I have to do a manual merge of the 150 files which I changed in that week - which I can't and won't do.

My best approach so far was to create a patch for the changes and apply that to the "new" repo. But I didn't get around to create a patch that won't fail yet due to a tree mismatch. I have yet to find the right commit to start the patch info from.

Resolution

TL;DR: There is none. You can just choose between the lesser evil.

  1. You can use the merge method desribed here but it will replace the individual file history from the SVN with the one from your side-git (i.e. you can't lookup why this file has been changed 3 month ago if your other repo is just 2 months old). But on the positive side you still have your changes merged together in the global history via git log.

  2. The other option I ended up with was to copy and replace all the files in the "new" (aka SVN) repo with the current status of my git repo (via cp -vru but omitting the .git-folder and all generated files). This let me loose the history worth of one week but still let me look back into the past until the beginning of the project which I prefer. To ease the pain of this loss a bit I crafted a detailed summary of my doings in the commit message using git log --date=short --pretty="format:%cd - %s" --name-status which at least gives me the chance to go back to this entry and see a message with a description. But of course this won't work for file deletions and you can't know which change actually belongs to which part of the biiiig commit message.

Upvotes: 4

Views: 1719

Answers (2)

poke
poke

Reputation: 387527

I just tested this with a repository of mine. I created made a new clone which represents your client’s new repository. Then I copied the contents of an older version to a new folder, and initialized a repository in it. I added the contents, and made a few commits.

That way I had two repositories with no common commit.

Now, in the new repository, I added my copy (in the following: mine) as a remote and fetched its contents. Then I checked out a new branch to mine’s master:

git checkout -b new mine/master

So I had all the history of my separate repository accessible from this branch. Next I merged the updated master into my branch, using a recursive merge strategy but favoring our (new) changes for conflicts:

git merge master -s recursive -Xours

This will automatically merge everything and in case of conflicts it will automatically resolve those by just using our versions, effectively throwing away the changes in master.

So, you should end up with a merged branch and all the history from both repositories is still there.

Upvotes: 3

che
che

Reputation: 12263

If I understand correctly, you have a situation like this:

remote repo:
A - B

your repo
C - D - E - F

Where commit A is actually identical to C, and commit B to D (in regard to files contained). I belive that what might work is simply rebasing your work on the latest remote commits, by doing something like

git rebase --onto B D

This should take your commits from D to your HEAD (e.g. F), and apply them as patches to B, resulting in this:

A - B - E' - F'

This then should be identical to your local changes, and could be confortably pushed to the remote repository.

Upvotes: 1

Related Questions