GitHub best practices for enterprise developers

This will be a running list of things that I found useful while working on enterprise projects. These can be good tips for other projects too but since there are usually a lot of developers working across enterprise codebases, it is a good idea to establish and enforce some Github (GH) practices in a timely fashion (when new repositories are created).

Use Trunk based development

Find more info here. This basically means using a main branch for all development work. Doing this helps you move your code fast to production.

The alternative is something like Gitflow which is a pain to work since you usually have to keep multiple branches in sync with this.

To achieve true trunk-based development, developers should have the necessary tools to fully test each PR in an integration environment. This can be achieved with a preview environment per PR. You might be familiar with how Vercel does this per PR but otherwise, your company might need to set up some in-house infra to provide this support.

Set up branch protection for main

Enable branch protection to ensure developers follow proper processes before merging code to main. This also ensures devs cannot directly push commits to main, unless you want that for certain developers, which is generally a bad idea. Any changes should go through a PR.

See Github docs on how to set this up.

Enable Squash and merge only for all GH repos

Github provides 3 different options to merge:

On larger projects, where you have a lot of developers working on a common repo, using any of these other options generally means you'll have a bunch of commits on main branch that don't make sense. I know some projects/developers tend to argue that each commit should be a semantic commit, sometimes this just adds too much pain for devs and hinders the ability to move fast.

Since developers should generally be advised to make smaller commits for quicker prototypes and better developer experience (DX), a PR with 50+ commits shouldn't land on the main branch the same way. With Squash merging, you only create 1 commit for 1 PR on main.

This is super valuable when you have a production issue and you have no idea where it came from and you have to now git bisect to find the root cause. With squash merges, you can pinpoint which PR introduced a bug much quicker!

Enable semantic PR checks

Prefer to use conventional commits on any commits to main branch. This extra piece of information on every commit can be super valuable if your repo is publishing packages to npm/Artifactory and you want to automate bumping major/minor/patch versions of packages. But even on a feature repo with web applications, this provides a nice overview of main branch commits indicating features, bug fixes, chores, etc.

Since you now have only squash merge enabled, you can enable every PR title to have the conventional commit prefix with a Github action PR check.

Have a CONTRIBUTING.md file for your repos

Create this file as a guide to provide newcomers with onboarding documentation. If you would rather have a common Onboarding document for a larger group with something like Docusaurus, link to that site from this file.

Create smaller GH teams and make them CODEOWNERS

When working in a polyrepo setup with multiple teams owning different repos, having a smaller GH team is nice since you can easily identify ownership. If you have a group of 100 people owning a functionality, it usually means no one owns it. A smaller group, who can be held accountable for an area, is better for quicker feedback cycles.

Add this GH team to the CODEOWNERS file to ensure any PR creations on the GH repo would need the code owner group approvals.

Use Renovate to automate dependency upgrades

In larger projects, keeping dependencies up to date is critical in the long term. Renovate makes this easy by creating PRs for you. It comes with a lot of baked-in defaults as well to make your life easy. For example, dependencies next and eslint-config-next should be upgraded together in NextJS projects. Hence Renovate creates a single PR for both of these updates and makes the necessary lock file updates for you. It also supports pnpm which is my go-to package manager for all new projects. Check their docs [here](https://docs.renovatebot.com/).

Enforce PR checks

Create PR checks for build, lint, test, format, typecheck etc. to make sure any commits going into the main branch are safe. Also, GitHub lets you mark these PR checks as Required so that developers cannot merge their PRs until these checks pass. You can find this under the branch protection setting for main