I have a problem. I started a project that uses Flask for back-end and React for front-end, in an attempt to learn both. Now, I want them in separate repositories, but still I want to use them in a third, single repository, which binds them together into an entire project. So I searched the Internet and found about Git Submodules. Now I want to play around with them. Let’s see what happens.
“What’s your problem again?”
Well, you might have noticed, that I’ve started this series of articles about React. This was just the beginning, since I want to play around with Python and a micro-framework like Flask (or something similar). However, I don’t want to copy all the code I have written for the React series in order to use it in my Python experiments. Also, it kind of sucks having a bunch of unrelated code in the repository.
That’s why I searched around to see how people are dealing with this. I would actually even prefer finding a way to use the code from one repository as a skeleton for the other repository: just clone it somewhere and start augmenting, without having the connection between them afterwards.
Ideally, at the end of this I’d have a bunch of independent repositories, one of which was derived from the React learning project I started, another one would be derived from a repository on GitHub, like tiangolo/uwsgi-nginx-flask-docker, and the third one would be with the server logic. Then I’ll plug in the Flask application repository in – the one from Sebastián Ramírez (tiangolo) – as well as the React repository. Something like this:
Let’s see if that works.
Creating the Deployment Project
Since the Deployment project is the wrapper, it would be the first one to create. I assume this makes things quite easy, since I expect it to be like creating a normal project.
Let’s just start with:
$ mkdir GitModulesFun $ cd GitModulesFun $ git init
The Front-end Project
This one is already there. The only thing we need to do is set it as a submodule to the deployment project. Let’s see how.
To be able to incorporate another repository as a module of GitModulesFun, I need the URL for the submodule repository. This URL can be relative, so I’ll just do this:
GitModulesFun$ mkdir web GitModulesFun$ cd web web$ git submodule add ../../entering21stcenturywithreact
This way I hope I created a folder in the main project, where the front end would be and added the repository there.
In fact, I created the folder, but the git command started complaining…
Relative path can only be used from the toplevel of the working tree
I’ll try that in the GitModulesFun directory.
That worked! But the name of the folder is the name of the other repo. I guess I’ll live with that.
Creating the Back-end Project
This part should be easy too. I have already prepared a running Flask application, so I just need to execute similar commands.
GitModulesFun$ git submodule add ../microframeworkBasedBackend
Oops, I dun goofed again:
Cloning into '/home/nikola/work/learn-docker/GitModulesFun/microframeworkBasedBackend'... warning: You appear to have cloned an empty repository. done. fatal: You are on a branch yet to be born
I think I need to commit something to that repository first.
An initial commit and a pull in the main project fixed everything!
Now let’s commit the .gitmodules file in the deployment project, like the manual says.
What is actually happening with these submodules?
I don’t really know how all this works. But I have an idea. First, I’ll edit the Dockerfile of the back-end project from the deployment project. Then I’ll play around with git commands. Like committing the change and then pushing it.
Committing
Ok, the commit command works as usual. It doesn’t matter that the origin of the project is on the same machine, it is considered remote. This means when I edit a file there, it is committed to the deployment project’s clone of the back-end. Now I can push this to origin and see it appear in the other directory.
Pushing
Let’s try to push to the origin/master in the back-end repository:
microframeworkBasedBackend$ git push origin master
Whoa, this spits a lot of errors:
Total 0 (delta 0), reused 0 (delta 0) remote: error: refusing to update checked out branch: refs/heads/master remote: error: By default, updating the current branch in a non-bare repository remote: is denied, because it will make the index and work tree inconsistent remote: with what you pushed, and will require 'git reset --hard' to match remote: the work tree to HEAD. remote: remote: You can set the 'receive.denyCurrentBranch' configuration variable remote: to 'ignore' or 'warn' in the remote repository to allow pushing into remote: its current branch; however, this is not recommended unless you remote: arranged to update its work tree to match what you pushed in some remote: other way. remote: remote: To squelch this message and still keep the default behaviour, set remote: 'receive.denyCurrentBranch' configuration variable to 'refuse'. To /home/.../microframeworkBasedBackend ! [remote rejected] master -> master (branch is currently checked out) error: failed to push some refs to '/home/.../microframeworkBasedBackend'
That’s actually kind of cool! Since in origin the master branch is checked out, you can’t really push into it. This is at least some kind of security I guess. Sure not really good one, but something…. It’s probably not really intended as real security either, rather than protection from corruption.
Conclusions
Git submodules is apparently a cool way to separate your project into smaller pieces. I guess this allows you to implement an access control, as well as separate concerns. For sure, I’ll be using it to reuse my old projects for new ones, but I should be careful not to break the rest. After all, this way my old project becomes a library, and anyone who uses it should maintain their work.
Well, that’s it for now folks,
Happy coding!
Want more? Take a look at my previous post: I don’t like dual boot machines anymore, but I still have one
Or the one where I make multipage site with React.