Feature Branch Workflow#
Encapsulate development work in dedicated, temporary branches of a Git repository. The main branch of the repository only contains known-good source code or configuration files, and the head of the main branch always matches the latest release or live deployment.
Linear Commit History#
Guidance
Developers MUST maintain the linear commit history of a Git repository as this simplifies code review and facilitates root cause analysis. Merge commits MUST NOT be used as they can hide risky code changes. Squash commits SHOULD NOT be used, either, as they discard historical context useful during root cause analysis.
Always use the --ff-only option to the git merge and git fetch
commands. Likewise, always use --rebase option to the git pull
command, or set pull.rebase to true in the Git configuration.
The Main Branch#
Guidance
The main branch of a Git repository MUST contain only released software versions or live (production) system definitions.
The main branch does not contain work in progress except during initial development, prior to the project’s initial release or deployment.
The Head of the Main Branch#
Guidance
The latest commit (or head) of the main branch of the Git repository MUST be the project’s latest release or current (active) configuration.
For infrastructure-as-code projects, staff should be able to redeploy a service from scratch given the head of the main branch of the Git repository, the service’s secrets and other runtime configuration parameters, and a recent copy of the service’s persistent data storage.
Feature Branches#
Guidance
All changes to published software or live services MUST be developed and tested in branches starting from the then-current head of the main branch of the project’s Git repository.
Limit a feature branch to a single deliverable.
The branch name succinctly describes the work, e.g., stepup-mfa,
mfa-enforcement-fixes. Git supports multiple feature branches being
worked simultaneously. To reduce the likelihood of a merge conflict
synchronize the main branch with the authoritative repository[1]
before creating a new feature branch, and configure
remote tracking
immediately after:
git checkout main
git pull --rebase origin main
git checkout -b new-feature
git push origin new-feature
Moving Work in Progress to a Feature Branch#
Guidance
If work in progress was mistakenly pushed to the main branch of the authoritative repository, the functional or task area lead MUST be notified within one (1) hour. No further action SHALL be taken except at their direction.
If instead the work in progress was mistakenly committed to the main branch but not yet pushed to the authoritative repository, move the work in progress to a feature branch:
Record the state of the working directory, preserving any new work or uncommitted changes.
git stash push --all --message WIP
Create a new feature branch from the current head of the main branch.
git checkout -b new-feature
Reset the main branch. In the commands shown below, change
original-headto a revision parameter specifying the latest approved release or configuration. The revision parameter could be a tag likev1.1.0, a symbolic reference likeHEAD~3, or a commit object likea1b2c3d4. For more information, refer to “Specifying Revisions” in thegit rev-parsecommand documentation.
git checkout main
git reset --hard original-head
Switch back to the new feature branch, and upload it to the authoritative repository.
git checkout new-feature
git push origin new-feature
Restore the new work or uncommitted changes saved at the beginning of this process.
git stash pop
Updating a Feature Branch#
Guidance
Merge commits MUST NOT be used as they can hide risky code changes. Squash commits SHOULD NOT be used, either, as they discard historical context useful during root-cause analysis.
Because Git supports work occurring simultaneously in the same branch of multiple clones of a repository, the original head of a feature branch can eventually no longer be the head of the corresponding remote-tracking branch. Pushing changes commited to the feature branch without accounting for recent changes to the remote-tracking branch would effectively delete other developers’ work from the Git repository. By default, Git will handle this situation by creating a merge commit and prompting the user to fix any conflicts (when the same file was modified in both branches).
Instead, rebase the feature branch on the head of the remote-tracking branch prior to merging to preserve the linear commit history of the Git repository:
Synchronize the feature branch with the remote-tracking branch.
git pull --rebase origin new-feature
Update the remote-tracking branch.
git push --force-with-lease origin new-feature
Merging a Feature Branch#
Guidance
Merging a feature branch with the main branch, thereby releasing a new software version or changing a live service’s configuration, MUST be approved by the Change Advisory Board.
Because Git supports work occurring simultaneously in multiple branches of a repository, the starting commit of a feature branch may eventually no longer be the head of the main branch. Merging a feature branch without accounting for recent changes to the main branch would effectively delete delivered code or approved changes from the Git repository. By default, Git will handle this situation by creating a merge commit and prompting the user to fix any conflicts (when the same file was modified in both branches).
Instead, rebase the feature branch on the head of the main branch prior to merging to preserve the linear commit history of the Git repository:
Synchronize the main branch with the authoritative repository.
git checkout main
git pull --rebase origin main
As a precaution, re-synchronize the feature branch with the authoritative repository.
git checkout new-feature
git pull --rebase origin new-feature
Rebase the feature branch on the main branch.
git rebase main
Update the remote-tracking branch.
git push --force-with-lease origin new-feature
Prune the merged feature branch.
git branch --delete new-feature
git push --delete origin new-feature
Tag the new head of the main branch with the new version number. This process may be automatic. For more information, refer to Continuous Integration.
In clones of the authoritative repository, update the main branch and release tags, and prune merged feature branches.
git checkout main
git pull --rebase origin main
git fetch --prune --tags