0

We didn't import our entire history when moving to git, and is making some operations difficult without the history of some of the files. I was thinking of importing some of the history into our tree using an orphan branch and then somehow attaching it to the root node. Is that possible? I realize I could attach it to a later one using a merge, but I was wondering if it could be done to somehow keep the original history timeline intact.

Adrian
  • 10,246
  • 4
  • 44
  • 110
  • There is no perfect solution. Merge is the best of all. Rebase rewrites the history. `git replace` makes a fake history, https://git-scm.com/blog/2010/03/17/replace.html. – ElpieKay Jan 11 '18 at 13:00
  • 1
    Read this article: http://axiac.ro/blog/merging-git-repositories/ It explains how to merge two Git repositories and keep the original commit dates. – axiac Jan 11 '18 at 13:05
  • You can probably use `git rebase`, for example as described [here](https://stackoverflow.com/questions/4981052/how-to-re-parent-in-git). One of the answers there also mentions the [git-reparent](https://github.com/MarkLodato/git-reparent) tool, which is another option. – larsks Jan 11 '18 at 13:42
  • `git rebase` is only practical if the commit/branch topology already in the repo is very simple. And even then it's not a *good* option, because it potentially changes the existing commits' content. – Mark Adelsberger Jan 11 '18 at 13:55
  • Possible duplicate of [Setting git parent pointer to a different parent](https://stackoverflow.com/questions/3810348/setting-git-parent-pointer-to-a-different-parent) – Joe Jan 11 '18 at 14:18

1 Answers1

1

There are a few options. Which is best depends on your needs, certain other users' belief that they can tell you which is best notwithstanding.

Option 1: You can use git filter-branch with a parent-filter to graft the current root onto the newly-imported history. This is a "history rewrite", so it requires coordination with all developers. My preferred way to do mass rewrites is:

  1. Everyone pushes all of their code. (It doesn't have to be merged, but has to be in the remote somewhere.)
  2. Everyone discards their clones
  3. You import the history and perform the rewrite
  4. Everyone makes new clones from the rewritten repo

Of course that kind of coordination may not be practical for your team. You could go ahead and do the rewrite, and just let everyone know that they have to recover all of their branches; but that's tedious, and it only takes one developer messing it up to potentially undo your rewrite work.

Also be aware all commits' IDs will change; so even if you can coordinate the cut-over, if you use those commit IDs (in release documentation, for example) then a rewrite may not be your best option.

For information on this option, see the git filter-branch docs (https://git-scm.com/docs/git-filter-branch); the parent-filter examples cover what you need.

As an aside, this is the closest thing to a "rebase" type solution that makes any sense at all. You can't easily rebase any but the simplest of histories, and rebase would re-calculate the content of each commit (which serves nothing but to create an opportunity for mistakes, since you don't actually want your commits' content to change).

Option 2: You could use git replace to "paper over" the break in history. The best way to do this is to have one commit of "overlap"; so import history up to and including a commit that's equivalent to your current root.

This avoids the history rewrite, but it doesn't propagate between clones and remotes; so each user would have to set it up locally in each clone. That's ok I guess; you could just set it up when you need it. But also be aware, there are some known quirks/bugs related to replace. See the git replace docs.

What I would do if pursuing this is to import the history, tag its tip, and put a note on the existing root with instructions on how to set up replace if needed in a given clone.

Option 3: merge. This isn't really an option within your constraints, but worth pointing out the pros and cons.

As you note, you can merge the imported history to your branch tip(s). The resulting history will not look quite normal, but at least the history will be there. You have to tell git to --allow-unrelated-histories, and you'll merge with the ours strategy (because you don't actually want the merge to change anything on your branch).

This sticks with very basic functionality of git, and doesn't rewrite any refs' histories, so it's simple and reliable. But I for one would not look forward to navigating a history that was stitched together in that way. IMHO it would be just as well to leave the histories separate (even if you import the old history into the same repo as an orphan), but again only you can determine how the pros and cons weigh for your team.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • Intersecting. Option 2 looks good, though I'm a little fuzzy on the document's quirks/bugs. This opens up more questions that I'll have to investigate further. Thanks. – Adrian Jan 11 '18 at 14:39