0

I'm convinced that git subtrees are not the right fit for my project and I'd like to convert my git subtree structure to a git submodule. How can I do this? With a structure:

main-repo
│   index.js
│   package.json   
│
└───vendor
    └───subtree-repo
        │   index.js
        │   package.json
DiverseAndRemote.com
  • 19,314
  • 10
  • 61
  • 70

2 Answers2

1

Maybe remove the directory and then add the submodule?

git rm vendor/subtree-repo
git submodule add git@github.com:blah/subtree-repo.git vendor/subtree-repo/
DiverseAndRemote.com
  • 19,314
  • 10
  • 61
  • 70
0

While it seems like the answer is clearly just what Omar Jackman suggests - and I don't see anything wrong with those steps - it does leave you with a history that may be less than ideal. In particular, I assume if you want the vendor directory moved to its own repo that some team will work directly with that new repo. If you want them to have full history, there's another step.

That step is to use git filter-branch with the --subdirectory-filter. Something along the lines of

git clone path/to/old_repo vendor_repo
cd vendor_repo
git remote remove origin
git filter-branch --subdirectory-filter vendor --prune-empty -- --all

Then validate the results; vendor_repo should contain a complete history of the changes that occurred in vendor. If it looks good, you can clean it up. (You probably want to remove the backup refs that filter-branch creates, the reflog, and the now-unreachable commits that are still cluttering vendor-repo; re-cloning may be a nice shortcut here.

So now you actually have a repo to use in the 2nd step of Omar's recommended procedure.

You still should probably keep the vendor history in the parent repo as well, because properly substituting the correct submodule commit reference into each historical parent-repo commit doesn't sound at all fun to me. I'm not saying it can't be done; you'd need to capture a map of parent-repo commits to vendor-repo commits and then use that map to drive a --tree-filter, or something similar. But is there that much to gain from doing it?

Either way, you can easily replace vendor with the current submodule commit and use the submodule going forward.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • >But is there that much to gain from doing it? Re:tree-filtering the result... All the discussions of splitting a subtree gloss over this point yet this is exactly what I'm looking to do in order to shrink the original repro. (The submodule is huge, but has only a couple dozen commits). My goal is to shrink the mainline repository (hundreds of commits), while keeping the history connections between the new repo and the submodule contents.) I'm specifically looking for a solution to this tree-filter problem. – Brad May 24 '17 at 17:19
  • 1
    Well, that is a lot more complicated. There are multiple ways to approach it, but they're all complex enough that I'd hesitate to suggest one without having time to test it out first. Generally speaking, you'd need a way to determine (for any original-repo commit) which vendor-repo commit should be included; and you'd need your tree filter to `rm` the existing directory, add the submodule, and check the submodule out to the identified commit – Mark Adelsberger May 24 '17 at 18:37
  • Thanks. In the end I gave up on rewriting all the history. Instead I manually dropped matching branch names across the submodule repo given there were relatively few commits to process. If I ever have to do it over hundreds of commits I'll revisit. – Brad May 26 '17 at 06:44