1

I have one git repository which is included within another git repository; how can I merge the inner one into the outer one permanently while keeping its commit history? For a more illustrative explanation, here's my directory structure:

[dev]
  > [ext]
        ...
  > [libs]
        ...
  > [tools]
        ...

The dev is the root directory of my git repository A, which excludes everything from the ext directory through a .gitignore rule. The ext, in turn, is the root directory of my git repository B. I would like to only keep the repository A going forward, and for it to include everything under dev, including the contents of ext, while merging the commit history of B into A -- so that I have just the one repository containing all of the contents and also all of the history of A and B both.

There are no submodules involved; the separation of the repositories is done just through the exclusion rule on the outer repository.

What's the best way to do this?

Brian61354270
  • 8,690
  • 4
  • 21
  • 43
mzi
  • 307
  • 3
  • 10
  • 1
    I think it's important to point out that the reason this question reduces to the problem of merging one repository into another repository is that you don't have a submodule, and from the point of view of both repos, the `ext` folder doesn't exist. The top rated answer to the linked question suggests using git-filter-repo to rewrite the history of the `ext` repo as if it did exist in that folder, and after doing that checking out any historical commit in the `ext` repo won't map to the root directory of your `dev` repo which would likely cause problems. – TTT Mar 17 '23 at 19:24
  • Side Note: if you decide to use git-filter-repo, that would also be a good time to possibly pull out any old binaries in the `ext` repo that you might wish were never committed in the first place. (Every time I've migrated a repo of any size into another, I've always found *something* we elected to remove from the history, while we are in there rewriting it anyway.) – TTT Mar 17 '23 at 19:27

2 Answers2

2

Start by moving the contents of repository B (in ext) to a new ext directory inside the repository (i.e. <project>/ext/ext).

$ cd ./ext
$ mkdir ext
$ for f in *; do git mv "$f" "./ext/$f"; done

This way the history of repository B will "remember" that it's source tree belongs in the ext directory during the next step.

Don't forget to commit this change.

After that, you can enter repository A (the root project), add repository B as a remote, fetch its unrelated history, and then create a merge commit that inherits from both revision histories. Do note that you will need to pass --allow-unrelated-histories to git-merge to allow the merging of unrelated history. The description of this flag reads:

By default, git merge command refuses to merge histories that do not share a common ancestor. This option can be used to override this safety when merging histories of two projects that started their lives independently.

All told, these are the commands to be run:

# Add "repo B" as a remote of "repo A"
$ git remote add ext_repo ./ext

# Fetch the unrelated history of "repo B"
$ git fetch ext_repo

# Create a commit with parents from both repos histories.
$ git merge --allow-unrelated-histories ext_repo/main
Brian61354270
  • 8,690
  • 4
  • 21
  • 43
  • 1
    That seems to be what I'm looking for, thank you. I was able to make this work on a sandbox repository where I'm just dry-running the script before actually running it on the real repositories. When I run it on the actual repositories, though, it stops on git lfs issues. I'll try to un-lfs the inner repository before the merge, then reapply lfs on it once it's merged into the main one. – mzi Mar 17 '23 at 20:45
0

First, backup. Second, push everything from ext to B:

cd ext
git push --all origin
cd ..

Remove subdirectory ext and also remove it from .gitignore:

rm -rf ext
`git var GIT_EDITOR` .gitignore

Now import B into A using git subtree:

git subtree add --prefix=ext URL-for-B master # or whatever branch you want to import
phd
  • 82,685
  • 13
  • 120
  • 165