Modern software is produced by teams whose members work on shared codebases, often across locations, time zones and organisational boundaries. Source control provides the technical and organisational foundation for this work. It records changes, supports parallel development, enables review and provides evidence about who changed what, when and why. In DevOps, source control is more than a backup mechanism: it is a controlled system of record from which builds, tests, releases and infrastructure changes can be automated.
This chapter examines Git-based collaboration, including repositories, commits, branches, merging, pull requests, code review, semantic versioning, trunk-based development and GitFlow. It also considers conflict resolution, access control, repository policies and the governance risks associated with poorly managed source code.
Learning Objectives
By the end of this chapter, students should be able to:
explain Git’s distributed version-control model;
create meaningful commits and use branches safely;
compare merging and rebasing and resolve conflicts;
design pull-request and code-review workflows;
apply semantic versioning to releases;
distinguish trunk-based development from GitFlow;
configure permissions and repository policies;
evaluate source-control practices in a professional DevOps environment.
1. Git as a Distributed Version-Control System
A version-control system (VCS) stores successive states of files and metadata about their changes. Git is distributed: each clone normally contains the project’s history, branches and tags. Developers can therefore inspect history, create commits and perform many operations without network access. A remote repository, such as one hosted on GitHub, GitLab or Azure Repos, acts as a shared collaboration point rather than the sole location of history.
Git distinguishes among three important areas:
Working tree: the files currently being edited.
Staging area (index): the proposed contents of the next commit.
Repository: the committed history stored locally or remotely.
A typical sequence is:
edit files → git add → git commit → git push
git add does not publish changes; it selects content for the next commit. git commit records a snapshot in the local repository. git push transfers local commits to a remote repository. Conversely, git fetch downloads remote history without changing the working tree, while git pull generally performs a fetch followed by integration, either by merge or rebase depending on configuration.
Git objects are identified using cryptographic object identifiers. Modern Git uses SHA-1 by default in many installations, although repositories can also use SHA-256. The identifier is a content-derived identity, not a sequential version number. A commit points to a tree representing file contents, its parent commit or parents, author and committer metadata, and a message.
Essential commands
Purpose
Typical command
Copy a remote repository
git clone URL
Inspect state
git status
View history
git log --oneline --graph
Stage a file
git add file
Create a commit
git commit -m "message"
Create or switch branch
git switch -c feature/name
Download remote references
git fetch origin
Publish a branch
git push -u origin branch-name
Integrate a branch
git merge branch-name
Compare changes
git diff
A commit should represent a coherent, reviewable change. Messages should explain intent, for example, Fix timeout handling in payment client, rather than updates. Small, cohesive commits improve review, rollback and fault diagnosis.
2. Branches, Merging and Rebasing
A Git branch is a movable reference to a commit. It is not an independent copy of the entire project. Creating a branch is inexpensive, which encourages developers to isolate features, fixes, experiments and release preparation.
A branch-based workflow commonly begins with an updated integration branch:
git switch main
git pull --ff-only
git switch -c feature/customer-export
The --ff-only option prevents Git from silently creating an unexpected merge commit when updating a local branch. Teams may instead use an explicit merge or rebase policy, but the policy should be understood and documented.
Merging
A merge combines histories. If the target branch has not advanced since the feature branch was created, Git may perform a fast-forward, moving the target reference to the feature tip. If both branches contain new commits, Git creates a merge commit unless the user chooses another strategy.
Merging preserves the actual branching history and is useful where auditability and explicit integration events matter. Its disadvantage is that repeated merges can produce a busy history.
Rebasing
Rebasing copies a series of commits onto a new base. The copied commits receive new identities because their parent history changes. Rebasing can create a linear history, but it rewrites commit history. Therefore, developers should not rebase shared commits unless the team explicitly permits it. Force-pushing rewritten public history can disrupt colleagues and automation.
A safe principle is: rebase private work to update it, merge or use a controlled integration method for already shared work. If force-pushing is necessary, git push --force-with-lease is safer than --force because it checks that the remote reference has not advanced unexpectedly.
Conflict resolution
A conflict occurs when Git cannot determine how to combine changes, commonly because two branches modify overlapping lines or a file is renamed and edited differently. A disciplined procedure is:
discuss the intended behaviour, not merely the text to retain;
edit the file into the correct final state;
run formatting, unit and relevant integration tests;
stage the resolution with git add;
complete the merge or rebase;
verify the resulting diff and history.
Conflict markers must never remain in committed source. Automated tests are especially important after conflict resolution because syntactically valid code may still contain incorrect combined logic.
Git branches converging through a pull request into the main branch
Figure: Git branches converging through a pull request into the main branch
Figure: A feature branch is tested and reviewed before integration into the main branch.
3. Pull Requests and Code Review
A pull request (PR), called a merge request in some platforms, is a formal proposal to integrate changes. It connects code, discussion, automated checks and approval records. A high-quality PR normally includes:
a precise title and description;
the problem and intended solution;
links to requirements or issue records;
tests performed and their results;
migration, security or operational considerations;
screenshots or logs where behaviour changes are visual or operational.
Code review is a socio-technical quality-control activity. Reviewers should examine correctness, maintainability, security, performance, observability, testing and compatibility. They should distinguish blocking defects from suggestions. Comments should address code and evidence rather than the character of the author.
A useful review sequence is to understand the requirement, inspect the overall design, examine implementation details, evaluate tests and check operational effects. Reviewers should avoid approving changes they have not understood. Authors should respond to every substantive comment and record decisions that future maintainers may need.
Branch protection can require successful builds, security scans, at least one or two approvals, signed commits, and an up-to-date branch before merging. “Required approval” should not be treated as a substitute for reviewer competence or automated testing.
4. Semantic Versioning and Release Identity
Semantic Versioning (SemVer) uses the form MAJOR.MINOR.PATCH, normally written as MAJOR.MINOR.PATCH. For a public API:
MAJOR increases for incompatible API changes;
MINOR increases for backward-compatible functionality;
PATCH increases for backward-compatible bug fixes.
For example, changing 2.4.1 to 2.5.0 indicates compatible new functionality, whereas removing a public method generally requires 3.0.0. Pre-release identifiers such as 2.5.0-rc.1 indicate a release candidate and have lower precedence than the corresponding final release. Build metadata, such as 2.5.0+build.17, may provide additional information but does not determine precedence.
SemVer depends on a clearly defined public API and honest compatibility assessment. It does not automatically describe database migrations, operational risk or every kind of deployment change. A supposedly patch-level change that invalidates stored data may be operationally major even if its code API is compatible.
Tags connect a release name to a commit. Release notes should identify changes, known limitations, migration instructions and security fixes. A reproducible release process should build from an immutable tag or commit rather than an unrecorded developer workspace.
5. Development Models
Trunk-based development
In trunk-based development, developers integrate small changes into a shared trunk, usually main, frequently. Short-lived branches may be used, but they are merged quickly. Incomplete functionality is controlled through feature flags, configuration or incremental implementation.
Advantages include reduced divergence, rapid integration feedback and a strong fit with continuous integration. Risks include unstable trunk commits if tests are weak, excessive feature-flag complexity and pressure to make changes too large for safe review. Effective trunk-based development requires automated tests, protected branches, small changes and disciplined ownership.
GitFlow
GitFlow traditionally uses a long-lived main branch for production, a develop branch for integration, feature branches, release branches and hotfix branches. It can suit scheduled releases, multiple supported versions or formal release stabilisation. However, its long-lived branches increase merge cost and delay feedback. For teams deploying continuously, GitFlow may conflict with the goal of integrating and releasing small changes frequently.
Concern
Trunk-based development
GitFlow
Integration frequency
Very frequent
Often delayed until integration or release work
Branch lifetime
Usually short
Several long-lived branch types
Release style
Continuous or frequent
Scheduled and staged
Main risk
Unstable trunk or flag debt
Divergence and merge complexity
Best fit
Continuous delivery
Controlled multi-stage releases
Neither model is universally superior. The appropriate choice depends on release cadence, regulatory controls, product architecture, team maturity and the cost of maintaining multiple versions.
6. Permissions, Policies and Governance
Repository governance combines identity, authorisation, technical controls and human accountability. Common roles include read-only users, contributors, maintainers and administrators. Least privilege means granting only the access required for a person’s responsibilities. Administrative rights should be limited and audited.
Important policies include:
protected default branches;
mandatory pull requests;
required status checks;
minimum reviewer rules and CODEOWNERS ownership;
prohibition of secrets in source code;
signed commits where identity assurance is required;
restrictions on force-push and branch deletion;
dependency and licence scanning;
retention and audit-log requirements;
documented emergency-change procedures.
Secrets must be stored in an approved secret manager, not in Git history, because deleting a file does not necessarily remove old commits from clones or caches. If a secret is committed, it should be revoked and replaced immediately; history rewriting may be useful but is not a substitute for revocation.
Governance also includes licensing and intellectual property. External code must be used according to its licence, and the organisation should track obligations for attribution, redistribution and source disclosure. Personal data should not be placed in test fixtures or commit messages without a legitimate and controlled purpose.
7. A Professional Collaborative Workflow
A practical workflow is:
create or select an issue with acceptance criteria;
update the local default branch;
create a focused branch;
implement a small change and add tests;
commit with an intention-revealing message;
push the branch and open a PR;
allow CI to run linting, tests, security checks and build validation;
respond to review and update the branch;
merge using the repository’s approved strategy;
delete the branch when appropriate;
tag and release through an automated, auditable process.
Commit granularity should support review and rollback. Squashing can create a clean integration history, while preserving individual commits can retain detailed development evidence. The decision should be consistent with the team’s audit and debugging needs.
A useful commit message convention may include a short imperative subject and a body explaining rationale. Conventional Commits, for example, use prefixes such as feat:, fix: and docs:. Such conventions can support automated release notes, but they do not replace human assessment of compatibility.
Northstar Payments is an illustrative online-payment company. Its team has eight developers, deploys weekly and maintains a Java service, infrastructure code and database migration scripts. Developers currently exchange patches through chat, and the shared repository permits direct pushes to main.
Problem
A production defect was introduced when two developers independently changed timeout handling. A manual merge retained one code path but omitted a required test. The team also discovered an API key in repository history. Release numbers were informal, so consumers could not determine whether an update was compatible.
Analysis
The problems were not caused by Git alone. They resulted from absent review controls, large and overlapping changes, inadequate automated tests, weak secret governance and undefined release semantics. The company’s weekly deployment schedule also made a heavily branch-oriented release model unnecessarily slow.
Approach
Northstar adopts short-lived branches and trunk-based development. The main branch is protected: direct pushes are disabled, two approvals are required for payment-service changes, and CI must pass. CODEOWNERS assigns payment and database files to specialist reviewers. CI performs unit tests, integration tests, static analysis, dependency scanning and a reproducible build.
The exposed API key is revoked and replaced through a secret manager. Repository history is assessed and cleaned where appropriate, but revocation remains the primary control. The team adopts SemVer, publishes migration notes and tags releases from approved commits. Feature flags are used for incomplete customer-visible functionality, with owners and removal dates recorded.
Outcome
The workflow reduces unreviewed changes and makes release provenance visible. Conflicts are smaller because branches are short-lived. The team does, however, monitor feature-flag accumulation and CI duration. It retains an emergency procedure requiring post-release review and an incident record.
Learning points
The case demonstrates that collaborative development is a system of practices. Branch strategy, tests, access controls, release naming, secret management and review quality must reinforce one another. A technically correct merge can still be an organisational failure if it bypasses accountability or introduces an unsafe operational change.
9. Challenges, Limitations and Contemporary Practice
Source control does not prove that software is correct. Tests may be incomplete, reviewers may miss defects and automated scans may produce false positives. Branch protection can also become counterproductive if approval rules are excessive or reviewers approve mechanically. Teams should measure outcomes such as escaped defects, review time, change-failure rate and recovery time, while avoiding incentives that reward meaningless commit counts.
Large binary files, generated artefacts and vendor dependencies may require specialised storage or package registries. Monorepos simplify cross-component changes but can require sophisticated build selection and ownership tooling. Many repositories now integrate software bills of materials, provenance attestations and signed build artefacts to strengthen software-supply-chain assurance.
AI coding assistants can accelerate drafting and test generation, but generated code requires the same review, licence assessment, security analysis and testing as human-written code. Prompts or source fragments may expose confidential information if the tool’s data controls are not understood. AI output should be treated as an untrusted contribution, not as evidence of correctness.
Best-Practice Checklist
Keep the default branch protected.
Make changes small, coherent and testable.
Pull or fetch before beginning significant work.
Never commit secrets or personal data.
Use mandatory review and meaningful CI checks.
Prefer short-lived branches for continuously delivered systems.
Resolve conflicts by discussing intended behaviour.
Do not rewrite shared history without an agreed process.
Tag releases and document compatibility and migrations.
Audit permissions, dependencies and repository activity.
Review generated or AI-assisted code critically.
Chapter Summary
Git provides distributed history, inexpensive branching and controlled integration. The working tree, staging area and repository have different purposes, and commits should capture coherent intent. Merging preserves integration history, while rebasing can simplify private history but rewrites commit identities. Conflicts require both technical resolution and behavioural verification.
Pull requests combine discussion, review, automated checks and approval. Semantic Versioning communicates public API compatibility, although it does not capture every operational or data-migration risk. Trunk-based development supports frequent integration; GitFlow can support scheduled or multi-version releases but introduces longer-lived branches and greater merge cost. Repository governance requires least privilege, branch protection, secret management, licensing awareness and auditable policies. Effective collaborative development is therefore a socio-technical discipline connecting source code with quality, security, release management and organisational accountability.
Key Terms
Git: A distributed version-control system.
Repository: A directory containing versioned content and its history.
Working tree: The files currently checked out for editing.
Staging area: The proposed contents of the next commit.
Commit: A recorded snapshot with metadata and parent history.
Branch: A movable reference to a commit.
Remote: A named reference to another repository location.
Merge: Integration of two lines of development.
Rebase: Reapplication of commits onto a different base.
Conflict: A change combination Git cannot resolve automatically.
Pull request: A reviewed proposal to integrate changes.
Code review: Structured evaluation of a change by other developers.
CI: Automated validation performed when changes are integrated.
Trunk-based development: Frequent integration into a shared main branch.
GitFlow: A branch model using feature, development, release and hotfix branches.
Branch protection: Rules restricting direct or unsafe changes.
Least privilege: Granting only the access necessary for a role.
Feature flag: A control that enables or disables functionality separately from deployment.
Repository policy: A documented technical or governance rule for repository use.
Review Questions
Short Answer Questions
What are the working tree, staging area and repository in Git?
Why should developers avoid rebasing commits already shared with colleagues?
What is the purpose of a pull request?
State the meaning of MAJOR, MINOR and PATCH in Semantic Versioning.
Give two controls that can protect a default branch.
Long Answer Questions
Explain Git’s distributed model and describe a complete feature-branch workflow.
Compare merge and rebase, including their effects on history and collaboration.
Explain how a team should resolve a source-code conflict safely.
Compare trunk-based development and GitFlow, and identify suitable contexts for each.
Discuss how code review, CI and repository governance work together to improve software quality.
Analytical / Application Questions
A team deploys daily but maintains long-lived feature branches. Analyse the likely risks and recommend a more suitable development model.
A developer accidentally commits a production credential and then deletes the file in a later commit. Identify the security implications and specify the correct response.
A library adds a backward-compatible function, fixes a bug and removes an existing public function in the same release. Analyse the SemVer implications and explain what additional release information consumers need.
Multiple Choice Questions with Answers
Question 1
Which Git area contains changes selected for the next commit?
A. Working tree
B. Staging area
C. Remote repository
D. Object cache
Correct Answer: B. Staging area
Question 2
What does git fetch normally do?
A. Deletes local branches
B. Downloads remote references without integrating them into the working tree
C. Stages all modified files
D. Creates a release tag
Correct Answer: B. Downloads remote references without integrating them into the working tree
Question 3
Why is rebasing shared public commits risky?
A. It removes all file contents
B. It prevents testing
C. It rewrites commit identities and can disrupt collaborators
D. It automatically exposes secrets
Correct Answer: C. It rewrites commit identities and can disrupt collaborators
Question 4
Which action is most appropriate after manually resolving a merge conflict?
A. Commit without testing
B. Remove the repository history
C. Run relevant tests, stage the resolution and complete the merge
D. Force-push immediately
Correct Answer: C. Run relevant tests, stage the resolution and complete the merge
Question 5
Under Semantic Versioning, removing a public API function normally requires increasing which component?
A. PATCH
B. MINOR
C. Build metadata only
D. MAJOR
Correct Answer: D. MAJOR
Question 6
Which characteristic best describes trunk-based development?
A. Frequent integration into a shared trunk
B. Permanent isolation of every feature
C. A mandatory release branch for every commit
D. Direct unrestricted pushes to production
Correct Answer: A. Frequent integration into a shared trunk
Question 7
Which control most directly prevents direct unreviewed changes to main?
A. A larger local clone
B. Branch protection requiring pull requests
C. Renaming the branch
D. Deleting commit messages
Correct Answer: B. Branch protection requiring pull requests
Question 8
What is the correct primary response when a secret is committed to a repository?
A. Only delete the visible file
B. Revoke and replace the secret
C. Rename the repository
D. Add the secret to .gitignore and take no further action
Correct Answer: B. Revoke and replace the secret
Question 9
What is a principal purpose of a pull request?
A. To replace all automated tests
B. To provide a formal integration, discussion and review point
C. To encrypt every source file
D. To create a new programming language
Correct Answer: B. To provide a formal integration, discussion and review point
Question 10
Which statement about code review is most accurate?
A. Approval guarantees defect-free software
B. Review should focus only on formatting
C. Review should consider correctness, security, tests and operational effects
D. Only the original author should review the change
Correct Answer: C. Review should consider correctness, security, tests and operational effects