Merging two git repositories to obtain linear history
git, merge
Solution
Fixing the results of `git filter-branch`
If you have a repository that looks like this:
D---E---F--
\
A--B--C--D'--E'--F'--M <-master
and you want the result to look like this:
A--B--C--D'--E'--F' <-master
then you can simply force `master` to point to `F'`:
git checkout master
git reset --hard <sha1-of-F'>
This will cause commits `D`, `E`, `F`, and `M` to become unreachable, effectively deleting them (they will be garbage collected after a while).
Starting over from scratch
Assuming you have two repositories that look like this:
- old: `A--B--C <-master`
- new: `D--E--F <-master`
and you want the result to be:
- combined: `A--B--C--D'--E'--F' <- master`
then you can perform the following steps:
Initialize the `combined` repository:
git init combined
cd combined
git remote add old url:/to/old
git remote add new url:/to/new
git remote update
At this point your `combined` repository looks like:
A--B--C <-old/master
D--E--F <-new/master
Note that the two branches aren't connected in any way.
Set your `master` branch to point to `C`:
git reset --hard old/master
Now your repository looks like this:
old/master
|
v
A--B--C <-master
D--E--F <-new/master
Find the sha1 of `D`:
d=$(git rev-list --reverse new/master | head -n 1)
Import `D` into your working directory and index by reading the contents of the commit
git read-tree -u --reset $d
commit the contents of `D` using the same commit message, author, date, etc. as the original `D` commit:
git commit -C $d
Now your repository looks like this:
old/master
|
v
A--B--C--D' <-master
D--E--F <-new/master
cherry-pick the rest of the commits:
git cherry-pick $d..new/master
Now your repository looks like this:
old/master
|
v
A--B--C--D'--E'--F' <-master
D--E--F <-new/master
Clean up:
git remote rm old
git remote rm new
Now your repository looks like this:
A--B--C--D'--E'--F' <-master
Problem
I have two git repositories and a lot of untracked changes between them: ``` ftp --> C-- (untracked changes) --D / \ git A--B--C <-- old/master \ \ \ new/master --> D--E--F ``` How can I merge old repository into new repository to have a linear history like ``` A--B--C--D--E--F ``` EDIT: inspired by How can I combine Git repositories into a linear history? I've done: ``` git clone url://new new cd new/ git remote add old url://old git fetch old git reset --hard origin/master git filter-branch --parent-filter 'sed "s_^\$_-p old/master_"' HEAD git push origin master ``` Only problem is that every commit from new/master was doubled (due to change of parent I think) so I've now (M is merge commit) ``` D---E---F-- \ A--B--C--D'--E'--F'--M ``` How can I easily remove unnecessary commits (D - F and maybe M)?