Branching and Merging Strategy
Categories:
Problem
In a GitOps setup with Ansible, managing changes across multiple environments like development, staging, and production requires a structured approach to avoid errors, ensure testing, and maintain security. Without clear branching policies, teams risk deploying untested code, conflicting changes, or unauthorized modifications to critical branches.
Context
GitOps practices involve using Git as the single source of truth for infrastructure and application configurations. In Ansible-based projects, this means storing inventory, playbooks, and variables in a Git repository, in a so-called Ansible inventory project. Branches can represent different environments, allowing changes to be promoted via merge requests (MRs). Protected branches in tools like GitLab or GitHub enforce reviews, approvals, and CI/CD pipelines before merges, ensuring changes are vetted and tested automatically.
Solution
Implement a branching strategy that aligns with GitOps principles, using environment-specific environment branches and merge requests for promotions. Enforce policies with protected branches to maintain control and auditability.
Follow these guidelines:
Define Core Branches: Create permanent branches for each environment. These are so-called environment branches. It is important that they match an environment consisting of hosts that are part of the same Ansible environment group.
master
: Serves as the stable, long-term branch that reflects the latest production state after successful promotions.development
: For ongoing development and feature work.staging
: For testing changes before production.production
: Represents the live production environment; only merge from staging after approvals.
Branching Policies:
- Feature branches: Create short-lived branches off
development
for new features or bug fixes (e.g.,feature/add-new-playbook
). - Hotfix branches: For urgent production fixes, branch directly from
production
(e.g.,hotfix/issue-12345
). - Avoid direct commits to environment branches; always use MRs for changes.
- Feature branches: Create short-lived branches off
Merging Workflow:
- Develop and test in
development
. - Merge from
development
tostaging
via MR for integration testing. - Merge from
staging
toproduction
via MR after approvals and successful CI/CD runs. - Finally, merge
production
back tomaster
to keep it updated. - For hotfixes: Apply to
production
first via MR, then backport to other branches.
- Develop and test in
Protected Branches:
- Configure branch protection for all
environment branches and for
master
in your Git platform (e.g., GitLab):- Require MR approvals (e.g., at least 2 reviewers).
- Enforce passing CI/CD pipelines before merging.
- Restrict who can push or merge (e.g., only admins for
production
). - Prevent force pushes and branch deletion.
- Configure branch protection for all
environment branches and for
Automation Integration:
Benefits
- Consistency and Safety: Reduces deployment risks by enforcing reviews and automated testing.
- Traceability: MRs provide an audit trail of changes and approvals.
- Scalability: Supports team collaboration without overwriting work.
- Rollback Ease: Environment branches allow quick reverts if issues arise.
Alternatives (Optional)
While Git Flow or GitHub Flow are common, they may not align perfectly with GitOps’ environment-based promotions. A simpler trunk-based development could work for smaller teams but lacks the staged promotion needed for regulated environments; the described strategy is preferred for Ansible GitOps setups requiring clear separation.
Examples and Implementation
In a typical Ansible GitOps project, structure your repository with branches representing environments. Use merge requests to promote changes, triggering CI/CD pipelines that run Ansible playbooks for deployment.
Here’s an example Git workflow visualized with Mermaid:
gitGraph commit id: "Initial commit" branch development checkout development branch staging checkout staging branch production checkout production checkout development commit commit commit id: " " tag: "1.0.0" checkout staging merge development tag: "1.0.0" checkout production merge staging tag: "1.0.0" commit id: "Production release 1.0.0" checkout main merge production tag: "1.0.0" checkout production branch hotfix-12345-fix-something commit id: "Hotfix applied" tag: "1.0.1-hotfix-issue-12345" checkout main merge hotfix-12345-fix-something tag: "1.0.1-hotfix-issue-12345" checkout development merge hotfix-12345-fix-something tag: "1.0.1-hotfix-issue-12345" checkout staging merge hotfix-12345-fix-something tag: "1.0.1-hotfix-issue-12345"
This diagram illustrates:
- Initial setup of branches.
- Development work merged to staging, then production.
- A hotfix applied to production and backported to other branches.
- Final merge to
master
for a stable record.
To implement in GitLab:
- Navigate to Repository > Branches > Protected branches.
- Set
production
as protected, requiring MRs and approvals. - Configure
.gitlab-ci.yml
to run Ansible jobs on merge events. For example:
stages:
- deploy
deploy_to_staging:
stage: deploy
script:
- ansible-playbook -i inventory/staging site.yml
only:
- staging
Additional Information
- Ansible Inventory Project: A structured collections of files used for managing hosts and configurations. It typically includes inventory files, playbooks, host configurations, group variables, and Ansible vault files.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.