When working in version control, changes are added to branches in small chunks, known as commits. Each commit contains a snapshot of your working folder, with a message describing what's changed since the last snapshot.
Because commits are often represented in a diffing tool by comparing one revision against another, there's a common misconception that commits are represented as a delta, which leads to the question "Can I run a deployment containing just the changes from one commit?" This is not only bad practice, but is a misunderstanding of how version control works.
In this article, we'll explore why you should avoid this practice, how to manage deployments from branches, and why you should be wary of any tool which allows you to deploy changes from a single commit.
Each branch exists as a sum of all its commits
As outlined in our guide on Salesforce DevOps, a branch is just a series of commits documenting the history of the state of a repository. It's common to have a branch, usually
master, that represents the latest version of your org's metadata.
There are usually then myriad other branches that roughly correspond to features that are in active development. Each of these
feature branches consist of of a snapshot of master at the point the branch was created, then a cohesive series of granular commits that comprise the feature. Each of these commits builds on the last, and together they comprise the in-progress feature.
It's also common to maintain a 1:1 mapping between a branch and an org - usually the master branch is mapped to your production org, and any feature branch will be associated with a corresponding dev sandbox or scratch org. Once a feature is complete and its associated changes have been reviewed, it can be merged back into master and deployed back to your org.
Each branch is a complete representation of the state of your metadata - whether that be master (representing the latest releasable version of your entire org) or a feature branch (representing the state of your org with an in-progress feature).
When using version control as source of truth, it's important to make sure that your org is an accurate reflection of the metadata in the branch - without this, the source of truth is some combination of the live org and the contents of your branch. This makes it very difficult to reason about the state of your org. Whereas with version control as source of truth it's easy - looking at your branch and commit history will give you a single, documented definition of your org's metadata. It also means that in a disaster recovery or rollback scenario, it's obvious what metadata needs to be pushed to your org.
Treating version control as source of truth is a long-standing and well understood industry best practice. For this reason, all deployments in Gearset are designed to treat version control as source of truth, whether manual, or as part of an automated CI job.
Why is deploying an isolated commit bad practice?
Actually, deploying an isolated commit is fine. Whenever you take the current state of a branch and deploy all changes from it, this is what you're doing - you're taking the latest commit in that branch, which is a full snapshot of your metadata at that point in time, and pushing it to an org.
However, when most people talk about deploying a single commit, they're referring to deploying just the changes between that commit and the previous commit.
Let's take a look at an example to demonstrate why you should avoid attempting to deploy changes like this. Enter our in-house Salesforce developer, Jason.
Jason creates a new feature branch off master. He starts by making a change to the Account object, by adding a new field to record what discount a customer received -
The image above shows the difference between the branch before and after this commit. If, at this point, Jason wanted to run a deployment from this branch to his integration sandbox, he can do so without issue. The only change he is deploying is this new field.
Jason now adds another new field on the Account object,
DiscountRatio. This field is a formula field, and references two other fields on the Account object: the new
DiscountValue and a pre-existing field,
The image above shows the difference between the branch after commit 2. If, without having deployed commit 1, Jason now attempts to deploy just commit 2 in isolation, what will happen?
The deployment will fail because the
DiscountRatio field is referencing a field which doesn't exist in the org:
DiscountValue. Jason now has to work out why the deployment failed and spend valuable development time solving an entirely preventable problem.
If Jason had run a full deployment of his branch, incorporating both commit 1 and commit 2, the deployment would have been successful.
This is a very simple example, but it clearly highlights the pitfalls of attempting to deploy the changes made in a single commit, rather than the full state of the branch. At best it introduces inconsistencies between your org and your branch, and at worst it increases the chances of breaking things and giving misleading deployment results.
Incidentally, if Jason was using Gearset to run this deployment, Gearset would have automatically warned him of this missing dependency and how to solve the issue as part of its problem analysis.
Why you should be wary of any tool which allows commit-by-commit deployments
Some Salesforce deployment tools allow you to deploy only changes from a single commit in isolation. In fact, they encourage it as a faster and easier way of working with version control.
You should be wary of this approach.
It may seem faster at first glance, but it dramatically increases the risks of complex deployment issues or merge conflicts further down the line which can be extremely costly to fix.
A much safer approach, more in-keeping with modern DevOps, is to include every change in a branch in your comparisons and deployments.
The overhead of getting your branch and org in a consistent state is initially higher, but the ROI on this up-front investment will be realised with the many hours saved by not having to debug repeatedly failing CI jobs due to metadata inconsistencies and missing dependencies.