Branching Strategy: Modified GitHub Flow
My teams employ a modified GitHub Flow branching strategy to streamline feature development and ensure a smooth deployment process. In GitHub Flow, every developer works on a feature branch and submits changes through a pull request (PR).
Besides GitHub Flow, there’s also Git Flow and other strategies. Git Kraken has a great article on comparing different methods.
Here’s a breakdown of how I’ve tailored this flow to my general needs:
1. Main Branches:
- dev/prod: This is our shared development and production branch. It reflects the most recent version of the code and serves as the base for feature development.
- Developers are expected to merge into this branch only after features have been reviewed and tested.
2. Personal Development Branches:
- Every developer is assigned their own development branch in the format name/dev (e.g., john/dev).
- All feature development stems from this branch, and before merging features, developers are required to merge the latest updates from dev/prod into their personal dev branch. This practice ensures their work is always in sync with the team’s progress.
3. Feature Branches:
- For each new feature or bug fix, create a new branch from your name/dev branch with a descriptive name prefixed by name/feature (e.g., john/feature-add-sidebar).
- Keep your feature branches focused—smaller, more manageable changes are easier to review, test, and merge.
Branch Naming Conventions
Naming branches in a clear and consistent way helps everyone on the team understand the purpose of the work being done at a glance. Here’s our branch naming scheme:
- Feature Branch: name/feature-[short-description] (e.g., alice/feature-contact-form)
- Hotfix Branch: name/hotfix-[short-description] (e.g., bob/hotfix-fix-404)
- Release Branch: release/[version-number] (e.g., release/1.2.0)
This structure ensures that branches are well-organized, easy to understand, and identifiable in GitLab.
Merging Process
The process of merging branches is critical to maintaining a stable codebase. Each developer must follow these steps to ensure their changes are fully integrated into the shared project:
- Merge Updates from dev/prod: Before merging a feature branch into your name/dev, pull the latest changes from dev/prod. This ensures your branch is up to date with the latest developments.
- Resolve Merge Conflicts: If any conflicts arise during the merge, resolve them in your local environment. Test thoroughly to ensure that all conflicts are resolved without breaking any functionality.
- Pull Request (PR) to dev/prod: Once your feature is complete and all conflicts are resolved, create a pull request into dev/prod. A tech lead or another team member will review and approve your work. This peer review process catches mistakes, bad patterns, or unintentional bugs and encourages team collaboration.
- Automatic Deployment: Upon merging into dev/prod, the changes are automatically deployed to our dev environment via GitLab pipelines, providing instant feedback on how the new code interacts with the full project.
Peer Reviews and Code Quality
Regardless of your skill level, code reviews from a peer or tech lead are required before any merge into dev/prod. Peer reviews improve code quality, reduce bugs, and encourage knowledge-sharing across the team. Even the most experienced developers can miss minor issues, and a second set of eyes ensures that everything is up to standard.
Continuous Integration (CI)
Within the git origin (BitBucket, GitHub, GitLab) pipelines are set up to automatically run tests and deploy changes once they are merged into dev/prod. This ensures we have a robust continuous integration (CI) process, making sure new features are fully integrated and tested before hitting production.
Next Steps
The next part of our Git documentation covers Git Message Structure and Templates, where we outline the structure of commit messages. This structure helps create a clear and navigable Git history, making it easier to track what’s been done and why.
By sticking to this workflow, we ensure that every developer’s contributions are properly tested, reviewed, and integrated into the broader project in a clean, predictable, and efficient manner. It encourages accountability, collaboration, and maintains a codebase that’s easy to manage even as the project scales.