1

I need to merge two git repositories by rebasing the root of the second repository onto the head of the first one.
While doing so, it should keep:

  • the commit history
  • all author dates + names
  • all tags
  • unmerged (feature) branches
  • merged branches
  • the two repositories have common files (same file name) and the content was changed in both repos

How can I achieve this?

This only needs to be done once and I don't need to keep the second repository after the merge.

Note: You can use the linked repositories to test your solution.


Here's an example:

merge-test-first:

My first (examplary) repository looks like this (https://github.com/Pro/merge-test-first):

* fcc6649 (HEAD -> master) J1
| * ba0ecb9 (branch_I1) K1
|/  
* 91bf6a4 I1
* acacd68 (tag: tag_H1) H1
|\  
| * 40bf845 (branch_B1) F1
| * 3ea2925 D1
* | 3780004 G1
| | * f7a61eb (branch_D1) E1
| |/  
| * aae948d C1
|/  
* 739d400 B1
* 6717e64 A1

(Output of git log --oneline --abbrev-commit --all --graph --decorate --color)

Graph for first repo

It contains a branch (branch_B1) with base B1 and then merged into master as H1 and two branches branch_D1, branch_I1

merge-test-second:

The second repository, which should be merged and then rebased onto merge-test-first/master/HEAD has some similar structure (https://github.com/Pro/merge-test-second):

*   28e726a (HEAD -> master) I2
|\  
| * 46f9d71 (branch_D2) G2
* | 2ae8b4d H2
| | * 606a346 (branch_E2, tag: tag_F2) F2
| |/  
| * bed8db1 E2
|/  
* e94c6d7 (tag: tag_D2) D2
| * 8a98058 (branch_B2) C2
|/  
* 82cb3ee B2
* 1b12fdf A2

Graph for second repo

Final result should be:

A2 from the second repo should be rebased onto J1 from the first repo, including all the commits, author dates and branches and merges:

*   (HEAD -> master) I2
|\  
| * (branch_D2) G2
* | H2
| | * (branch_E2, tag: tag_F2) F2
| |/  
| * E2
|/  
* (tag: tag_D2) D2
| * (branch_B2) C2
|/  
* B2
* A2    
|   
* J1
| * (branch_I1) K1
|/  
* I1
* (tag: tag_H1) H1
|\  
| * (branch_B1) F1
| * D1
* | G1
| | * (branch_D1) E1
| |/  
| * C1
|/  
* B1
* A1

So I need to add the red edge somehow (note: the tags are not visible in this graph, but should also be rebased):

final graph

What I tried so far:

  1. Simple rebase:
    git rebase test-first/master test-second/master
    This doesn't preserve the merges and author dates, nor other branches from the second repo
  2. Solution for keeping author dates and merges:
    http://axiac.ro/blog/2014/11/merging-git-repositories/
    Summary: it uses --preserve-merges and then some git magic (git filter-branch ...) to rewrite the author dates.
    This solution also doesn't copy over all the unmerged branches of the second repo.
  3. How do you merge two Git repositories?
    Only merges a single branch
  4. Setting git parent pointer to a different parent
    Git grafs only change the parent, but don't take into account the differences if two files have been changed in both repos and should be merged.
Community
  • 1
  • 1
Stefan Profanter
  • 6,458
  • 6
  • 41
  • 73
  • 1
    A piece of advice: don't try to preserve the committer dates. They are changing because the commit is changing and this is future information people want to know. The important thing to preserve is the *author and author date*. – Schwern Apr 15 '16 at 17:05
  • Thanks, I changed the question to use author dates, that's what I meant. – Stefan Profanter Apr 15 '16 at 17:24
  • Do you necessarily want a *rebase*, or is it sufficient to insert a parent link while leaving the attached trees unmodified? If it *is* sufficient, you just need to create a graft / replace-entry, then run `filter-branch` to copy all the commits (using `--tag-name-filter cat` to re-point tags). – torek Apr 16 '16 at 04:28
  • Both repositories contain some files which have the same name and source and were modified in both repos. So I suppose a rebase is required? Or does the parent link handle this correctly? – Stefan Profanter Apr 16 '16 at 07:47

0 Answers0