Source Control Overview
Source control (or version control) is fundamental to modern DevOps practices. It provides a single source of truth for both application code and infrastructure definitions. This guide covers best practices for implementing effective source control strategies across cloud providers.
Popular Source Control Systems
GitHub - Widely used for public and private repositories with excellent CI/CD integration
GitLab - Self-hosted or SaaS platform with built-in CI/CD capabilities
Azure DevOps - Microsoft's comprehensive DevOps platform with integrated work tracking
Bitbucket - Atlassian's Git solution that integrates with their suite of products
Sections within Source Control
Goal
Following industry best practice to work in geo-distributed teams which encourage contributions across organizations
Improve code quality by enforcing reviews before merging into main branches
Improve traceability of features and fixes through a clean commit history
Enable GitOps workflows for infrastructure and application deployments
Support multi-cloud environments with consistent practices
Modern Source Control Patterns
Trunk-Based Development
Trunk-based development is a source control pattern where developers collaborate on code in a single branch (trunk/main), using feature flags and other techniques to disable incomplete code in production.
Key characteristics:
Short-lived feature branches (typically less than 2 days)
Frequent merges to the main branch (at least daily)
Comprehensive automated testing
Feature toggles to manage incomplete features
# Example workflow
git checkout -b feature/add-monitoring
# Make changes
git commit -am "Add Prometheus metrics endpoint"
# Pull latest changes from main
git pull origin main --rebase
# Run tests
npm test
# Push and create PR
git push -u origin feature/add-monitoring
# PR is reviewed and merged quickly (same day if possible)
Monorepo vs. Multirepo
Monorepo
A monorepo stores multiple projects in a single repository.
Advantages:
Simplified dependency management
Atomic changes across projects
Unified versioning
Easier code sharing and refactoring
Disadvantages:
Can become unwieldy for very large projects
Requires more sophisticated build tooling
Access control is less granular
Multirepo
A multirepo uses separate repositories for different projects or services.
Advantages:
Clear ownership boundaries
Fine-grained access control
Focused scope per repository
Independent release cycles
Disadvantages:
Challenging cross-project changes
Dependency management complexity
Version compatibility issues
Decision criteria:
Team size and structure
Project architecture (monolith vs microservices)
Deployment frequency requirements
Security and access control needs
GitOps Workflow
GitOps uses Git repositories as the source of truth for declarative infrastructure and applications.
Core principles:
The entire system is described declaratively
The canonical desired system state is versioned in Git
Approved changes can be automatically applied to the system
Software agents ensure correctness and alert on drift
Example GitOps workflow with Flux:
# Example Flux GitRepository resource
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: infrastructure
namespace: flux-system
spec:
interval: 1m
url: https://github.com/organization/infrastructure
ref:
branch: main
Infrastructure as Code Management
Best practices for managing Infrastructure as Code in source control:
Structure repositories effectively
Separate application code from infrastructure code
Organize by environment, region, or component
infrastructure/ ├── modules/ # Reusable infrastructure components ├── environments/ # Environment-specific configurations │ ├── dev/ │ ├── staging/ │ └── production/ └── platform/ # Shared platform resources
Version infrastructure resources
Use semantic versioning for infrastructure modules
Tag stable infrastructure releases
# Tag infrastructure releases git tag -a "infra/v1.2.0" -m "Added VPC peering and updated security groups"
Handle state files securely
Never store state files with secrets in source control
Use remote state with appropriate access controls
# Terraform remote state example terraform { backend "s3" { bucket = "terraform-state" key = "prod/network/terraform.tfstate" region = "us-west-2" encrypt = true dynamodb_table = "terraform-locks" } }
Manage secrets properly
Use secret management services (AWS Secrets Manager, Azure Key Vault)
Consider solutions like SOPS or Vault for encrypted secrets in Git
General Guidance
Consistency is important, so agree to the approach as a team before starting to code. Treat this as a design decision, so include a design proposal and review, in the same way as you would document all design decisions (see Working Agreements and Design Reviews).
Creating a new repository
When creating a new repository, the team should at least do the following:
Agree on the branch, release, and merge strategy
Define the merge strategy (linear or non-linear)
Lock the default branch and merge using pull requests (PRs)
Agree on branch naming (e.g.
feature/add-monitoring
oruser/your_alias/feature_name
)Establish branch/PR policies
Configure CI/CD pipelines to run on PR creation
Set up automated linting and security scanning
For public repositories the default branch should contain the following files:
Conventional Commits
Using conventional commits improves repository readability and enables automated versioning:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Common types include:
feat
: A new featurefix
: A bug fixdocs
: Documentation changeschore
: Routine tasks, maintenancerefactor
: Code change that neither fixes a bug nor adds a featuretest
: Adding or correcting testsci
: Changes to CI configuration
Example:
feat(api): add endpoint for user authentication
Implement JWT-based authentication for the API service.
BREAKING CHANGE: `Authorization` header now required for protected routes
Contributing to an existing repository
When working on an existing project:
git clone
the repositoryReview the project's README.md and CONTRIBUTING.md files
Understand the team's branch, merge and release strategy
Follow the established workflow and coding standards
# Clone the repository
git clone https://github.com/organization/project.git
# Create a feature branch
git checkout -b feature/implement-monitoring
# Make changes, commit using conventional commits
git commit -m "feat(monitoring): add Prometheus metrics endpoint"
# Push changes and create a pull request
git push -u origin feature/implement-monitoring
Multi-Cloud Source Control Practices
When managing infrastructure for multiple cloud providers:
Unified Repository Structure
Use consistent naming conventions across providers
Organize by capability rather than by provider when possible
Provider Abstractions
Consider using abstraction layers in IaC
Implement consistent tagging across cloud providers
Cross-Provider Testing
Test infrastructure changes across all targeted cloud environments
Use matrix CI/CD jobs to validate across providers
Mixed DevOps Environments
For most engagements, having a single hosted DevOps environment (i.e., Azure DevOps) is the preferred path, but there are times when a mixed DevOps environment (e.g., Azure DevOps for Agile/Work item tracking & GitHub for Source Control) is needed due to customer requirements. When working in a mixed environment:
Use integrations between systems where available (Azure Boards GitHub App)
Manually reference work items in commits with standard formats (e.g., AB#123)
Ensure that the scope of work items / tasks align with PR's
Consider automation tools like GitHub Actions to sync state between systems
Document the workflow clearly to avoid confusion
Resources
Git - Official Git documentation
Azure DevOps - Microsoft's DevOps platform
GitHub - GitHub documentation and guides
GitLab - GitLab documentation
Learn Git Branching - Interactive Git tutorial
Conventional Commits - Commit message convention
GitHub Flow - A lightweight branch-based workflow
GitOps Principles - Core GitOps concepts and practices
Last updated