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)?

Original source

Related problems