We interviewed hundreds of software developers to understand their development workflows and how they work with GitHub. Using our own product, we also scanned thousands of GitHub repositories for our customers.
This list of GitHub best practices is derived from the insights we gleamed from those experiences. These best practices are still applicable even if you use something other than GitHub for source control, because they’re all about improving code quality, security, and writing good code.
This guide is for anyone in the Engineering organization looking to improve developer workflow and productivity, as well as code quality and security.
Those responsible for putting together team-wide standard practices and policies would benefit greatly from this guide, but even if you’re a developer not “in charge” of driving such standards, you will find these practices applicable and useful to remember.
Regardless if you use Gitflow or any other git branching model, it is always a good idea to turn on git branch protection to prevent direct commits and ensure your main branch code is deployable at all times. All commits should be pushed to master through pull requests.
Sometimes you commit code using the wrong email address, and as a result GitHub shows that your commit has an unrecognized author. Having commits with unrecognized authors makes it more difficult to track who wrote which part of the code.
Ensure your Git client is configured with the correct email address and linked to your GitHub user. Check your pull requests during code reviews for unrecognized commits.
When you’re dealing with dozens, hundreds, or more repositories and engineers, it’s nearly impossible to know who owns which parts of the codebase and need to review your changes.
Even in smaller teams you’d still have code owners – for example, front-end code changes should be reviewed by the Front-End Engineer.
Use Code Owners feature to define which teams and people are automatically selected as reviewers for the repository.
Secrets, or secret keys or secret credentials, include things like account passwords, API keys, private tokens, and SSH keys. You should not check them into your source code.
There are also tools for scanning secrets in repos and prevent them from getting into repos.
Pushing dependencies into your remote origin will increase repository size. Remove any projects dependencies included in your repositories and let your package manager download them in each build. if you are afraid of “dependencies availability” you should consider using a binary repository manager solution like Jfrog or Nexus Repository. Or check out GitHub’s Git-Sizer.
We strongly recommend against committing your local config files to version control. Usually, those are private configuration files you don’t want to push to remote because they are holding secrets, personal preferences, history or general information that should stay only in your local environment.
A .gitignore file is a must in each repository to ignore predefined files and directories. It will help you to prevent secret keys, dependencies and many other possible discrepancies in your code. You can choose a relevant template from Gitignore.io to get started quickly.
Over time, for various reasons, we find ourselves with unmaintained repositories. Sometimes developers create repos for an ad hoc use case, a POC, or some other reason. Sometimes they inherit repos with old and irrelevant code.
In any case, these repos were left intact. No one is doing any development work in those repos anymore, so you want to clean them up and avoid the risk of other people using them. The best practice is to archive them, i.e. make them “read-only” to everyone.
Your manifest file contains information about all packages and dependencies in your project and their versions. The best practice is to specify a version or version range for every package and dependency listed in the manifest. Otherwise, you can’t be sure which version will get installed during the next build, and consequently your code may break.
Even when everyone on your team are using the same packages, reusing code and tests across different projects can still be difficult if the packages are of different versions.
If you have a package that is used in multiple projects, try at a minimum to use the same major version of the package.
Tasks lists provide a way for you totrack to-dos directly within comments, issues, and even MarkDownfiles (*.MD) within your repository (users must have write access to therepository to make changes to MarkDownfiles).
Tasks lists provide an excellent way tocapture a high-level overview of a task or issue, as well as keep othersupdated on its state. Make sure to take advantage of this powerful new feature!
Adopting a consistent branch naming convention is essential to keeping your repository organized as your team grows in size. An efficient naming convention will allow you to keep merge conflicts at a minimum while ensuring your developers are as productive as possible.
While there are many branch naming conventions, one of the most popular ones is known as git flow:
Every time one branch is merged into another, the branch that is merged in becomes stale, assuming further work isn’t being done in it.
While it may seem useful or even necessary to keep the extra data on hand, the reality is that stale branches are abandoned 98% of the time and simply clutter up your project.
Even if you delete a branch when you shouldn’t have, you can restore it - and if you don’t trust GitHub’s restore feature, chances are it’s safe on somebody’s computer, thanks to the magic of distributed versioning.
Don’t be a branch hoarder: delete your stale branches.
Let’s say you’ve finally completed some work on a long-outstanding branch and you’re ready to merge it into master. You pull from remote, hit merge, and suddenly you’re faced with a barrage of merge conflicts.
You failed to keep your branch up-to-date with the branch you’re attempting to merge into. Lots of commits went by and some conflicted with your changes... now you’re faced with spending time and energy resolving an unnecessary amount merge conflicts.
The best practice here is to ensure that you’re consistently merging your base branch into your current branch as you work, especially if it’s a long-outstanding branch.
While it might seem obvious, it’s worth mentioning in a comprehensive list of best practices... Be sure to remove contributors from your organization that are no longer contributing to your codebase.
If you remove somebody from your organization for any reason, revoke their GitHub access immediately as well. Even in completely amicable situations, it’s better safe than sorry!
Security alerts are another feature new to GitHub. You can read about them here, but the gist is that GitHub now tracks reported security vulnerabilities in some dependencies and will even suggest fixes for you.
This is turned on automatically for all public repositories, but if your repository is private, you’ll need to opt in manually.
Developers spend a lot of time working with git and GitHub, so investing in improving your GitHub practices makes a lot of sense. Implementing best practices in this guide could help the team improve developer productivity and reduce security risks.
Ensuring consistent adoption of best practices could be very challenging, especially in fast-growing or large teams.
The ways people try to solve this problem, like writing down policies in a shared document or wiki, sending mass emails from time to time to entire teams, Slacking them in the team channel, or hoping code reviews will catch everything, are not consistently effective – let alone scalable.
Whether you decide to build in-house or use a purpose-built commercial tool, investing in automating best practice adoption is a good idea and will help you prevent costly mistakes.
Best practices for writing git commit messages - cheatsheet included. Read how to optimize git commit messages to improve your development productivity.
Check out: Best practices on managing secrets using AWS or Hashicorp Vault. Also see: sample code we use at Datree.io to inject secrets into our application.