简体   繁体   中英

Git repo subfolder as subtree of another repo?

My company is working on migrating from SVN to Git - part of the reason is to take advantage of deployment software that works using Git as a source. We're using a single repository (monorepo) for all components of our application stack.

We're also looking at using PM2 for NodeJS app management/deployment. Since this can use a git repository for deploying updates, we'd love to use it - but only a single subdirectory of our repository is really needed to be deployed.

Is it possible to create a git repository that references just a single subdirectory of another git repo as a submodule / subtree?

Something like this - with Repo A being the main monorepo and Repo B being the repo containing only the NodeJS stuff from Repo A.

RepoA\
  Component1\
  Component2\
  DelphiApp\
  NodeJSApp\
  PHPStuff\
  Configurations\
  Utilities\
RepoB\
  NodeJSApp\ <--subtree/submodule back to NodeJSApp in RepoA

For git submodule , the short answer is no:

  • You either have a repository or you don't.

    • If you don't have the repository, you can clone it, and now you do. But you have the repository , not some subdirectory of the repository.
  • Now that you do have the repository, you either have some commit in it, or you don't.

    (Commits are identified by hash IDs—those big ugly strings of letters and numbers—and since humans are bad at remembering random strings of letters-and-numbers, and for other purposes, each repository has some set of names that each remember one hash ID. The names are good for you , but what Git really needs is the hash ID.)

    • If you don't have the commit, you can have your Git connect to another Git that also has the repository. Your Git can ask their Git about commits that they have, that you don't, and get those commits into your Git repository. Now, if they have the commit, so do you.
  • Now that you have the repository and the commit, you have all the files. A commit is (or more precisely, contains / refers-to and obtains) a complete snapshot of every file.

You don't have to use all the files. You can extract only the files you care about. But that's a lot harder than just using git checkout name to get the commit whose hash ID is stored in name name , which gets you all the files. The easier way to go is probably the way to go.

Other options

Note that Git has various procedures for dealing with subtrees. Some of them are captured into a contributed script called git subtree , for which there is a tutorial here that seems OK (at a quick glance). Using git subtree to split out the library now and then can get you just what you want. I don't recommend using subtrees in general though—it's better to split "library-like" code into a completely separate repository.

You can then either use multiple independent repositories, which is pretty simple to do, or use git submodule to select particular commits from the "library" repository, in either the "using-library" repository that has all the rest of the code, or in a "gets-submodules-only" superproject that has both the using-the-library and providing-the-library repositories as its (now two) submodules. That is, you either have:

  • superproject: contains Component1/* , Component2/* , DelphiApp/* , PHPStuff/* , Configurations/* , and Utilities/* , and refers to a submodule NodeJSApp/ , plus
  • library: contains files * that will live in a NodeJSApp/ directory as controlled by the superproject

Or, you have:

  • superproject: refers to a submodule app/ , and refers to a submodule app/NodeJSApp/

  • app: a Git repository containing Component1/* , Component2/* , etc., but does not refer to NodeJSApp/ at all. The superproject will extract these to app/ so that their full names will be app/Component1/* , app/Component2/* , etc.

  • library: a Git repository containing files named * that make up the library. The superproject will extract these to app/NodeJSApp/ so that their full names will be app/NodeJSApp/* .

The only difference between these, besides being forced to find everything under app/ for the second approach, is that with the second approach, you'll manage the two independent Git repositories—one for the app itself, and one for the library—independently, then use the superproject to say: build the project by extracting hash app from the app Git repository, and hash lib from the library Git repository. That is, neither subproject needs to be aware of Git-ness and hash IDs: only the superproject has to care about that.

With the first approach, you eliminate the need for the app/ top level directory, but now every commit you make in the main app records a hash ID that Git should extract in the library submodule before you build. If you update the library, you then need to record the new hash ID in the superproject. This is the same as before, except "the superproject" is the app itself , rather than a third Git repository that merely contains the two submodule references.

The two-Git-repositories, one that has files and acts as superproject to pick out a particular commit in the submodule, is the more common approach. It's sometimes more convenient. The "one superproject to supervise everything else" method sometimes makes more sense , but it's definitely less common.

yes, you can. Just do not use submodules. subtree or subrepo can help you there. You can make the 'NodeJSapp' a subtree or a subrepo in repoA. It will efficiently map the directory to the corresponding one-directory repository.

This way you'd be able to use repo A as a main one with atomic operations, like branching, across the whole tree, including the NodeJSApp directory. You would need to push and pull it periodically into RepoB. Submodules do not work this way. Subtrees do, but in some limited facion. Subrepos could be the best available opensource choice.

There are custom ways to do it as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM