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)?
To combine two separate Git repositories into one, add the repository to merge in as a remote to the repository to merge into. Then, combine their histories by merging while using the --allow-unrelated-histories command line option.
In the Conceptual Overview section, we saw how a feature branch can incorporate upstream changes from main using either git merge or git rebase . Merging is a safe option that preserves the entire history of your repository, while rebasing creates a linear history by moving your feature branch onto the tip of main .
The most basic and powerful tool to do this is the git log command. By default, with no arguments, git log lists the commits made in that repository in reverse chronological order — that is, the most recent commits show up first.
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).
Assuming you have two repositories that look like this:
A--B--C <-master
D--E--F <-master
and you want the result to be:
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
Just check out your branch and run:
git reset --hard **SHA-OF-F'**
That will remove M
and D
-F
from your branch.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With