9

Everybody understands something different by "merge git repositories", so here is my case. We had a TFS repository and we have checked out the sources at one point in time and made an initial git commit. Then we did normal development in git (branching, merging, etc.). The problem is that in the new repository we do not have history in out git repository and we would like to fix that. Therefore I have converted whole TFS repository to git repository and now I need to merge the converted TFS repository with the current git repository.

As becomes obvious from the above description the repositories are independent from git standpoint, but from logical point of view they have one commit in common (the commit that became initial commit to current git repository).

How do I merge those repos without losing history of any of them? I could just take the converted TFS repo as base and then cherry pick changes from master of the current repo, but that would not import all the branches that were created in the current repo.

Tomasz Grobelny
  • 2,666
  • 3
  • 33
  • 43

2 Answers2

3

EDIT: my previous answer does not lead to nothing good. git rebase was not meant to do this. However, something similar already happened on stackoverflow: Merging two git repositories to obtain linear history

You can try with this procedure:

git init combined
cd combined
git remote add old url:/to/old
git remote add new url:/to/new
git remote update

You will have a new repo, with references to both repos. then

git reset --hard old/master

This will make the master branch point to the master branch of the old repo. You can now cherry pick all commits from the master branch of new repo

git cherry-pick <sha-1 of first commit on new repo>..new/master

We are were we started: master branch is ok, but what about other branches in the new repo? Well, you do not need your old repo anymore, so

git remote rm old

then, say you have a branch named 'branch1' in your new repository.

git checkout branch1
git rebase master

This should change history of branch1 to make it start from master (the combined master, containing history from your imported repo), and rebasing should happen without conflicts. Check history is consistent with gitk, then you can force push with

git push -f new master
git push -f new branch1

You have to be sure that history is ok before forcing push, since this will change history upstream (keep a backup of both new and old repos to recover if needed)

Community
  • 1
  • 1
p91paul
  • 1,104
  • 10
  • 26
  • What do you mean by "open branch"? Wouldn't subsequent rebases result in all commits from all those different branches being stacked up on one branch (oldmaster; assuming no conflicts)? – Tomasz Grobelny Aug 16 '13 at 11:26
  • no, branch newrepo/master will be rebased to start from oldmaster, then newrepo/branch1, etc. This assumes that in the old repo there was only one branch; By "open branch" I mean all branches different from master that you want to be rebased in your git repository. The final result should be that the content of oldmaster has been prepended to each branch in your new git repo. Eventually, before each rebase, you will need to switch to the branch you are rebasing. (git checkout newrepo/branch1; git rebase oldmaster) – p91paul Aug 16 '13 at 13:19
  • All branches in the newrepo come from one commit that was originally imported in to git, so I assume I have only one "open branch" even if later on many other branches were created from this starting point, correct? But my oldrepo contains a few branches for past stable releases, how does that change the situation? – Tomasz Grobelny Aug 16 '13 at 15:02
  • I tried rebasing and it failed on the first commit of the oldrepo - which indicates that something is seriously wrong here (probably me who does not understand how rebasing works). – Tomasz Grobelny Aug 16 '13 at 15:17
  • edited my answer. Sorry, I had some doubt about the rebase thing, probably to work it needs to have some commits in common. Try now, I think it should work. – p91paul Aug 17 '13 at 13:53
  • (Sorry for the delay.) Unfortunately it does not work as expected. I get a ton of "error: addinfo_cache failed for path 'path/to/file'" messages. – Tomasz Grobelny Sep 06 '13 at 12:15
  • seems like this error messages is linked to a git bug. Check your git installation is up to date, and/or try git mergetool. – p91paul Sep 07 '13 at 22:24
  • Not sure this procedure can work when there are merge commits in the new remote. For me `git cherry-pick` failed at the first merge commit it encountered in the new remote: `error: commit 659ea21 is a merge but no -m option was given.` – Jean Paul Jan 15 '21 at 10:14
  • @jean-paul not sure what I took into consideration 7 years ago, but, no, probably I didn't think of merges. Probably because OP wanted a linear history, I must have assumed both repos did not have merges. – p91paul Jan 16 '21 at 11:08
0

This is how I did, not sure it is the correct way to do but at least that worked for me:

git clone url:/to/new
cd repo
git remote add old url:/to/old
git remote update
git rebase --committer-date-is-author-date old/master

That was it. Now if there are other branches maybe you will also need to rebase them on master, which may not be so trivial.

The git history of the new repo became flat but for me that was OK when looking at git log -p --graph

The major issue was that I became the committer of all the commit of the new repo. To avoid that, you can look at the answer to a similar question which uses git filter-branch --parent-filter instead of git rebase: https://stackoverflow.com/a/44078243/4374441

Jean Paul
  • 1,439
  • 18
  • 21