I want to extend on another question I had: Merge two Git repositories and keep the master history
I have succeeded in merging 2 different repo's into one repo. I needed a rebase to do this successfully. The master is correct, but I also want to keep the merge history. Is this possible?
I have 2 repositories:
This is the result after rebasing. The times of the top repo are the rebase-time. The original date is lost!
This is how I did it:
# Assume the current directory is where we want the new repository to be created
# Create the new repository
git init
# Before we do a merge, we have to have an initial commit, so we'll make a dummy commit
dir > Read.md
git add .
git commit -m "initial commit"
# Add a remote for and fetch the old RepoA
git remote add -f RepoA https://github.com/DimitriDewaele/RepoA
# Do the same thing for RepoB
git remote add -f RepoB https://github.com/DimitriDewaele/RepoB
# Rebase the working branch (master) on top of repoB
git rebase RepoB/master
# Rebase the working branch (master with RepoB) on top op repoA
git rebase RepoA/master
Is it possible to have something like this? (painted solution!!!)
I would like to keep the original time + the merge history.
UPDATE - ANSWER
The answer that worked best for me, was working with graft points. But other answers are also very usable in other use cases. I have added my results on github, so everybody can evaluate.
Answer 1: Best working in my case The 'graft' did reveal the correct working answer for me.
Answer 2 the "replace" option from "LeGEC" also gives good results for some use cases. One anomaly stayed for me:
Answer 3: Worth adding The answer from 'VonC'. I could not get the option '--preserve-merges working' in my case. This might work in other scenario's, but I did not test this furtner.
As you've discovered, rebase
isn't the command you want to use to stitch histories together (because it actually rewrites history). Early Git had a feature (hack) designed specifically for what you're trying to do: graft points. Even better, since 1.6.5 you can use git replace --graft
instead:
git checkout master
git replace --graft $(git log RepoB/master --format=%H | tail -1) HEAD
git replace --graft $(git log RepoA/master --format=%H | tail -1) RepoB/master
git reset --hard RepoA/master
(git log RepoA/master --format=%H | tail -1
returns the initial commit from RepoA
)
Technically you could skip the first replace
if you don't actually have anything of value yet in master
, yielding just history with RepoB + RepoA.
These commands create entries in refs/replace/*
that can be pushed and pulled to share your revised history with others. Or, if you don't care about preserving the SHAs of RepoA/RepoB, you can make the replacements permanent by running git filter-branch --all
to produce a "real" set of commits of the desired lineage.