Transforming a subfolder into a subtree or submodule
The first issue that comes to mind while thinking of the use cases of subprojects in Git is about having the source code of the base project ready for such division.
Submodules and subtrees are always expressed as subdirectories of the superproject (the master project). You can’t mix files from different subsystems in one directory.
Experience shows that most systems use such a directory hierarchy, even in monolithic repositories, which is a good beginning for modularization efforts. Therefore, transforming a subfolder into a real submodule/subtree is fairly easy and can be done in the following sequence of steps:
- Move the subdirectory in question outside the working area of a superproject to have it beside the top directory of the superproject. If it is important to keep the history of a subproject, consider using
git subtree split
, orgit filter-branch --subdirectory-filter
or its equivalent, perhaps together with tools such asreposurgeon
to clean up the history. See Chapter 10, Keeping History Clean, for more details. - Rename the directory with the subproject repository to better express the essence of the extracted component. For example, a subdirectory originally named
refresh
could be renamedrefresh-client-app-plugin
. - Create the public repository (upstream) for the subproject as a first-class project (for example, create a new project on GitHub to keep extracted code, either under the same organization as a superproject, or under a specialized organization for application plugins).
- Initialize a self-sufficient and standalone plugin as a Git repository with
git init
. If, in step 1, you have extracted the history of the subdirectory into some branch, then push this branch into the just-created repository. Set up the public repository created in step 3 as a default remote repository and push the initial commit (or the whole history) to the just-created URL to store the subproject code. - In the superproject, read the subproject you have just extracted but, this time, as a proper submodule or subtree, whichever solution is a better fit and whichever method you prefer to use. Use the URL of the just-created public repository for the subproject.
- Commit the changes in the superproject and push them to its public repository, in the case of submodules, including the newly created (or the just modified)
.
gitmodules
file.
The recommended practice for the transformation of a subdirectory into a standalone submodule is to use a read-only URL for cloning (adding back) a submodule. This means that you can use either the git://
protocol (warning: in this case, the server is unauthenticated) or https://
without a username. The goal of this recommendation is to enforce separation by moving the work on a submodule code to a standalone separate subproject repository. In order to ensure that the submodule commits are available to all other developers, every change should go through the public repository for a subproject.
If this recommendation (best practice) is met with a categorical refusal, in practice, you could work on the subproject source code directly inside the superproject, though it is more error-prone. You would need to remember to commit and push in the submodule first, doing it from inside of the nested submodule subdirectory; otherwise, other developers would be not able to get the changes. This combined approach might be simpler to use, but it loses the true separation between implementing and consuming changes, which should be better assumed while using submodules.