Question

I have two repositories, A and B. I want to copy all the files in A, with a subset of their history, into B. B has its own files with history that I'd like to preserve, too; it is not a fresh, new repository.

You see, A has 28,000 commits. All but the most recent 30 or so, I don't care about. For simplicity of discussion, let's say that I'm not interested in commits #1 through #27,970, but I would like to retain the history for commits #27,971 through #28,000.

I've tried two different approaches.

  • Squash commits #1 through #27,970 commits in A (using git rebase -i) into a single commit, and then git pull A into B. The trouble I ran into here as that during the rebase of A, there were a lot of errors about git being unable to apply certain commits. I'm not knowledgeable about these commits in A, so I was unable to fix them. (Plus, it was taking a long time to perform the rebase - many hours and I wasn't done yet.)
  • Download a snapshot (i.e., no history) of A at commit #27,970 and place that in B, and the do a git add and git commit for the fresh new files. Then create a patch from A (using git format-patch) for commits #27,971 throught #28,000, and apply that patch (using git apply) to B. This all seemed to work fine, except it did not maintain the history of commits for the given files. That is, after applying the patch, it appear that all changes from all 30 commits happened at once: the history was not preserved.

There's gotta be a simple way to do this!

Was it helpful?

Solution

So I looked into two possible options to do what you're looking for. One of them is to make a shallow clone of repo A, but according to the documentation:

A shallow repository has a number of limitations (you cannot clone or fetch from it, nor push from nor into it), but is adequate if you are only interested in the recent history of a large project with a long history, and would want to send in fixes as patches.

Not being able to do basic network options like push and fetch from a shallow repo sounds like a pretty big limitation, so I think this next option might be better for you. Instead of making a shallow repo, you could try making an orphan branch starting at commit master~29, then rebase commits master~28..master on top of it:

git checkout --orphan root master~29
git add .
git commit -m "Add your message here"

That will start your orphan branch off, with a new root commit that contains the state of your history at commit master~29. Next you'll want to rebase the descendant commits back on top (this will preserve history, except for the commit dates, which will necessarily be updated because of the rebase):

git rebase --preserve-merges --onto root master~29 master
# or `-p` for short
git rebase -p --onto root master~29 master

That will reconstruct the rest of master on top of your new root, while also preserving any merge commits. If you want to confirm that this new version of master is the same as the old one, just with a shorter history, then just do a diff immediately after the rebase:

git diff master@{1} master

I highly recommend that you test this one another clone first.

Documentation for orphan branches.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top