Merge two Git repos and keep the history

大憨熊 提交于 2019-11-28 06:32:05

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.

There are two options in git rebase that should be of interest in your case:

p
--preserve-merges

Recreate merge commits instead of flattening the history by replaying commits a merge commit introduces.

--committer-date-is-author-date 

(from git am)

By default the command records the date from the e-mail message as the commit author date, and uses the time of commit creation as the committer date. This allows the user to lie about the committer date by using the same value as the author date.

Test if the second rebase doesn't yield a better result with:

git rebase -p --committer-date-is-author-date RepoA/master

This answer suggests a different way to use RepoB as the active repo, and still have access to RepoA history :

use git replace

# start with a regular clone of the active repo :
$ git clone RepoB

# add repoA as a remote :
$ git remote add -f history https://github.com/DimitriDewaele/RepoA

# get hash of *initial* commit on repoB :
$ git log --oneline origin/master | tail -1
abcdef Initial commit

# get hash of last commit on repoA :
$ git log --oneline history/master | head -1
12345 Merge branch 'develop'

# use 'git replace' to tell git to stitch histories in the log :
$ git replace abcdef 12345

Note : this operation is done on your machine, not on the remote repositories, so should be repeated on all new clones.

Variant :

You may push RepoA:master to RepoB under a new name (e.g : RepoB:history/master), then you can use git replace abcdef history/master, on commits which are all stored in RepoB.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!