We have scenario where for any application config changes in Prod, we create 2 PRs: 1 for implementation and another for rollback. We create these in advance. Then, we get them reviewed and approved.
We don't have anyone to review the PR during the change window. So, we have to create PR in advance and get approvals.
Let's say, master branch contains a config file app.properties with below 2 properties:
test.base.certificate=abcd
test.base.key=abcd
We create the implementation PR as below:
- create implementation branch from master.
- Update the properties with new values as below:
test.base.certificate=efgh
test.base.key=efgh - Commit the changes.
- Push the changes to remote.
We create the rollback PR as below:
- Create rollback branch from master.
- Update the properties with new values as below.
test.base.certificate=efgh
test.base.key=efgh - Commit the changes.
- Revert to old property values:
test.base.certificate=abcd
test.base.key=abcd - Commit the changes.
- Push the changes to remote.
Rollback PR doesn't show any differences in app.properties. This is because after the 2nd commit, there is no difference between the file in master and rollback branch.
During the Prod change window, we first merge the implementation PR and test. If any issues during testing, we merge the rollback PR to revert the changes.
I had to perform the rollback activity first time recently. After merging the rollback PR, I observed that the app.properties in the master branch still had the new property values:
test.base.certificate=efgh
test.base.key=efgh
At high level, it looks like that this approach should have worked. Does anyone have any idea why it didn't work? How to create the rollback PR in this case?
PS - I'm aware of git revert. However, I'm curious as why the above approach didn't work.
Thanks in advance!

My guess is that you think
git merge rollbackreplays the two commits unique torollbackonto the current branch (main). If git did that, the first commit would do nothing sincemainalready has that change. The second commit would restore the properties file to its old state. This is what you expected. But this is not howgit mergeworks.git mergedoes not replay commitsWhat
git mergedoes by default is called a three-way merge. As explained in an answer to another question:The git merge docs has a less detailed explanation, but explains exactly the behavior that is confusing you:
I believe the reason does this is for a few reasons:
rollbackwere a feature branch, you wouldn't want it to just override the changes made byimpl.git merge -s ort -X theirs rollaback, or by using other commands likecherry-pickorrebase, depending on what you exactly want.solutions #1:
git revertNix the
rollbackbranch and just usegit revert:This is simplest.
solutions #2: branch
rollbackfromimplIf for some reason you must do it via a PR, or for whatever reason must have a
rollbackbranch, then branchrollbackoff ofimpl, notmaster:It will look like this:
merging
implto deploy:merging
rollbackto rollback:Not only will
app.propertiesbe reverted as you expected, the git history is simpler AND a better representation of what happened. Compare it to the result of your current approach, which has two identical, redundant commits (2 and 3), and misleadingly splits into three branches at the beginning.It looks even better if you allow
fast-forwardmerges.Deploy ends up like this:
and rollback like this: