Is it possible to merge non-overlapping Git repositories that were imported from the same CVS source?

I have a number of repositories that are CVS imports done in the past by different people.

All of these repos have the same commit history, the same as in CVS, and fall back to the same original commit in CVS, but while the commits are obviously the same, they commit IDs. Later commits diverge because different changes were made in each of them, but their ancestors are identical and revert to the same original commits.

I checked out all of these repos into one new one. Looking at the branches (with gitk), I can see that they all do not overlap, even though they have the same revision history.

What I would like to do is somehow git to recognize commits that are the same, so the stories can be merged into one tree. Is it possible?


source to share

2 answers

Yes it is possible! And as usual with git, there are several ways to do this.

You need translations or refs for you . Here's a ref reference first:

  • Use git replace

    to replace all duplicated commits with their "canonical" versions. Select one repository commit version for authorization and then reapply git replace <other_repo_commit_hash> <primary_commit_hash>

    . When you do this, the stories will become connected.

And here is the vaccination method:

  • Create a text file named .git/info/grafts

    . There, each line should consist of a hash commit, then a space, and then a separate list of parent (s) elements, which should be of the form. So if you have two "identical" commits, A and A ', and they have children B and C, respectively, you would like to transplant C to A (giving A two children, B and C). You would do this by putting a C commit hash and then A on a line in the graft file. When you do this, the repository will look like this:

          A ---- B

  • Note that A 'is gone. In fairly newer versions of git, you can use git replace --graft

    to get graft-like functionality, although it will actually use refs replacement under the hood.

Once you are done grafting or creating replacement refs, you should have one associated story with everything in it. Now you want to run git filter-branch -- --all

over it to make the replacements permanent. You don't need to do any real rewrites, although you can if you want: only launching filter-branch

will make the replacements / grafts go away and leave a seamless story. Push the resulting unified branches (but not the old junk!) To the new git repository and you're done.



Thanks to @Borealid , this is how to merge branches with the same history. It works when stories have different commit IDs.

First write the records to a file .git/info/grafts

. Each line contains two ref commits A

and B

, where A

is the first commit in the branch and B

is its new parent. If, as in my case, each branch was moved to the same point, all records are the same B

. I had two such branches and my file looked like this:

209cbb0179ee490f4dbb7aaa6b7d7e32a1f4d21e 637bafd129d781516f9b1efbccd326484efecdb3
be007b20ac07770098701927730e01d965186b6e 637bafd129d781516f9b1efbccd326484efecdb3


Now check how it looks in gitk --all

. If it is already running, click <SHIFT><F5>

to restart. When you're happy that it looks as expected, keep making the changes permanent:

$ git filter-branch -- --all
$ rm .git/info/grafts
$ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
$ git reflog expire --expire=now --all
$ git gc --prune=now


The last three commands are taken from the git filter-branch




All Articles