You can use some package manager to share code between projects, 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 command

git 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 command

git 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 from 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 has 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 a submodule to the stage and create a new commit.

What is important?

You need to remember that changes made on the submodule don’t trigger changes in the parent repository. You need to push separately commits from both repositories. There is also the 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, they 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 a 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 the file in REPO2 on the new branch (repo2-test-branch), push changes to the server, create a 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 the 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 the 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! Now you know how to share code between projects. Have fun with submodules.