We've yet to give our readers a "peek behind the curtain" and discuss some of the ins-and-outs of our engineering practices at MojoTech. In this post, I'd like to begin to talk about some of our practices and the way we work from an engineering perspective.
There are many things we care deeply about that go a long way to making a software project run smoothly, and our usage of Git as a source code management tool is one of them.
The following is a section directly from our internal MojoTech engineering playbook and is presented in its entirety.
Git will be used as the source code management (SCM) tool here at MojoTech. Our projects are primarily hosted under the MojoTech GitHub organization, although some projects occasionally have other SCM hosting tools.
MojoTech has some specific usage patterns around Git that allow us to work as a team effectively and collaborate on projects in an efficient manner.
Git has no definitive rules on how branches must be named, and no branch name holds any special significance inherently. However, the community standard is to use a branch called
For MojoTech projects, the
One of the nice benefits of Git is that creating, working with, merging, updating, and deleting branches is trivial, cheap and easy. As such, developers are encouraged to create branches at will as they work on various features, bugs, and tinkering. Feel free to create branches as often as desired, and work out of those feature branches in your normal daily workflow.
Developers should never directly commit to the
- Create a feature branch off of master
- Make changes to implement the feature
- Submit a new Pull Request for those changes
- Have those changes peer code reviewed
- After approval, merge the Pull Request into the master branch
New feature branches typically should be created from an up-to-date
$ git checkout master$ git pull$ git checkout -b <new_branch_name>
There are occasions when you will create a new branch from a non-master branch as well. For instance, a developer may want to try several solutions for a problem by creating a new branch for each one from a common starting point.
To keep some form of consistency and legibility among open branches, developers should name their branches in the following format:
Some examples follow:
$ git checkout -b cpj/add_metrics_tracking$ git checkout -b cpj/fix_remember_me_input$ git checkout -b cpj/update_login_endpoint
This naming structure allows all developers to easily see which developer "owns" or created a particular branch, as well as gives general insight into what code changes live in that branch. Some developers also like to include the Pivotal Tracker ticket number in their branch name.
$ git checkout -b cpj/add_reset_password_feature_1234567
As engineers work on a feature branch, changes from other developers will most likely be merged into the
In simple terms, a
This may result in some conflicts as the commits are reapplied, and the
If the changes from
There will be times, usually after a code review process or while "cleaning up" a branch before you submitting as a new Pull Request that you will need to do an "interactive" rebase. The first few times you need to do this process, it makes sense to sit with another Mojo and walk through the process. We also made a video describing the process: https://www.youtube.com/watch?v=8ZXExlHBPoY
Git commits, like branches, are also cheap and easy to make. As such, developers should get into the habit of creating frequent commits along the way, instead of making one huge "big-bang commit" at the end of a feature's development cycle. Smaller commits are much easier to code review, rollback, and combine together later if needed, rather than the alternative of having to split a single large commit into multiple smaller commits.
Unlike Subversion commits which are immediately pushed to the repository, Git (which is a distributed system) commits are kept local to the user/machine who made them. Nothing is distributed to the central repository unless the developer specifically chooses to do so via
Git commits should be kept atomic, which means each commit should be self-contained, related, and fully-functional revolving around a single task or fix. Git makes this task easier by allowing you to save partial file changes in a commit. This means you don’t need to commit all changes to a single file at once. Instead, you can stage them in “hunks” that can contain many commits that reflect several changes to a single file.
"Self-contained, and related" means that commits should contain all changes and files related to the commit in question, and only those changes. A commit should not, for instance, contain code for adding a new input field to a form and also code for fixing a bug in a separate file tweaking a cache timeout setting. These should be two separate commits, not one single commit.
"Fully-functional" means that each commit along the way should be a fully buildable/passable stopping point. If anyone were to check out the Git history at a specific commit along the way, the application and code should still be fully functional, runnable, and passing all test suites.
Git commit messages should contain a shorter, succinct first line, followed by a single blank line, then any additional supporting descriptive paragraphs as desired.
The single, shorter first line allows for easy identification when viewing the
Often times, this single short line is all that is needed to describe what is contained in a commit. Other times, more supporting information and documentation are required, and the developer can feel free to use as much additional space as desired in the commit body.
Here is an example of a single line commit message:
Update the ASSET_HOST environment variable
Here is an example of a more lengthy descriptive commit message:
Fix regression bug with Remember Me featureThere was a bug ticket filed here #TK134AFKR where a userwas unable to "uncheck" the Remember Me checkbox on the loginscreen while.After research, it appears that certain older mobile browserswere not able to use the native JS touch library code we were usingso a polyfill method was added to make the feature work on anyolder mobile browser not supporting native touch calls.
Some developers also like to "tag" their first-line message as well for easier scanning the logs
[fix] Remove login timeout threshold`
[docs] Update deployment process documentation
This is optional unless your project's team leader decides to require or exclude it as a project policy.
A lot of times, tagging commits makes it easier for peer reviewers to quickly know your intent behind each commit. For example, if a commit is tagged
A "Pull Request" (PR) is the term used for a single or set of commits being marked as ready to review and merge into
Before submitting a PR, the developer should rebase their feature branch against
Commits should be ordered sequentially for easy review and grouped logically. Any "general supporting" commits should be reordered to the beginning of the commit sequence, followed by the detailed feature commits.
Commits should be squashed together (via
All developers on the project should actively participate in peer code review of open Pull Requests. This keeps the whole engineering team "in the loop" and aware of what other developers are working on and what moving pieces are changing in the application. Code review also is beneficial to everyone as more eyes on the code base will allow more bugs to be caught ahead of time. Developers are encouraged to leave specific comments and questions on changes, logic flow, business requirements, etc... related to the PR's code.
When code review is complete, and the developer team signs-off on approval of the code, and the code passes any required test suites, the PR request will be merged into the
Guides & Links