How to share code between projects

Development

How to share code between projects

Posted on

You have two projects, for example, web applications. Each of them has the same layout (images, colours, some components). And you don’t want to duplicate these files in each repository. Use Git submodules. In this post, you’ll learn how to do it.

You can use some package manager, for example, NMP in JavaScript world. But I don’t think that this is a proper way of using packages in the project. There is another way to accomplish that. You can create another repository with shared code and put it to the project repositories. How to do that?

Commit

Firstly, you need to know what a commit is and how it looks like. From Wikipedia:

A commit object links tree objects together into a history. It contains the name of a tree object (of the top-level source directory), a time stamp, a log message, and the names of zero or more parent commit objects.

Every commit in the repository is different, has a unique identification (or simply a hash). You can get this id with commandgit log. However, every commit has a long id or short (git log --pretty=format:%h), on the remote server (BitbucketGithub) you will see rather short than long id. Both of them are unique, so you can use them interchangeably.

So with every command git commit you create a unique snapshot of the current code in your repository. And this is important. You probably know that you can do git checkout to another branch, but also you can check out to a specific commit. To do that, simply run git checkout commit_hash. And from this point, you can create new branches, do commits and other commands which you normally do when you are on a branch.

What is a git submodule?

Git submodule is a normal repository with all the features that comes with git. And it’s very important to remember this.

How to add git submodule?

With a simple command git submodule add [<options>] [<repository>]. It’s very similar to commandgit clone so you can add the repository by ssh or https, define specific folder etc. That command will create an empty directory and add proper options to file.gitmodules. Why is the directory empty? Because submodule wasn’t initialized.

To get the code from the submodule you need to run git submodule update. It will download all files from the repository. Which branch? As it was said, It’s similar to the clone command, so you will have HEAD from the master branch. When you will push changes to the remote server, you will have a directory with submodule and hash of the last commit fro the master. When you will click on it, it will redirect you to the submodule repository. What is most important, the parent repository is storing only the hash commit of the submodule repository.

How to make changes to the submodule?

If you will change some files on the submodule and you will run git status, you will see “modified content”, but you cannot add this to the stage. Why? Because parent repository sees, that something has changed, but the hash of the submodule hasn’t changed. You need to go to the submodule directory and create commit. It is important to push this commit to the server, without it, you will be the only person that have this commit on the local machine. After this push nothing will change in the parent repository. Go back to it and run git status. You will see, that submodule has new commits. At this moment you can add submodule to the stage and create new commit.

What is important?

You need to remember that changes made on the submodule don’t trigger changes on the parent repository. You need to push separately commits from both repositories. There is also possibility to have submodule in the submodule. In that case you can use --recursive flag for git submodule update command. Also, after someone will clone your repository with submodules, he/she should use git submodule update --init to initialize and download submodule code.

Exercises

To get familiar with git submodules, I’ve prepared some exercises, which can be done in 10 minutes:

  1. Create repository (hereinafter referred to as REPO1), add some files, push them to the remote server (github/bitbucket).
  2. Create another repository (hereinafter referred to as REPO2), add some files, push them to the remote server (github/bitbucket).
  3. Add REPO2 as a submodule in REPO1 in src/common directory (all files from the REPO2 should be in src/common directory, not src/REPO2), push changes to the server.
  4. Clone REPO1 to another directory (hereinafter referred to as REPO1Copy), initialize submodules (hereinafter referred to as REPO2Copy).
  5. Modify file in REPO2 on the new branch (repo2-test-branch), push changes to the server, create new branch in REPO1 (repo1-test-branch), push changes to the server, create Pull Requests for both branches, check how they look like.
  6. Checkout to repo1-test-branch branch in REPO1Copy, pull changes from submodules.
  7. Modify file in REPO1 in branch repo1-test-branch, push changes to the server.
  8. Checkout to the first commit in REPO2, commit changes in REPO1 and push changes to the server.
  9. In REPO1Copy pull changes from the server.
  10. Checkout to master branch in REPO1, update submodules.
  11. Merge repo1-test-branch to master branch (through Pull Request), pull changes from remote master in REPO1 and REPO1Copy (observe, that you don’t need to merge repo2-test-branch to master branch, to have actual changes in the parent repository).

That’s it! Have fun with submodules.

Posted by: