I have a mercurial repository with two permanent branches, default and UAT. Every once in a while, we deploy (promote) a new version of our application to the UAT environment an
I believe the problem is similar to the problem in this question: merging doesn't work the way you think it works. Merging is only a question of comparing file-states, it's not a matter of applying changes from one branch onto another.
Your starting point is a history like this:
UAT: ... x --- y --- z
\
default: ..... a --- b --- c
where x
and y
contain the config settings for UAT and b
is the dummy merge with no config settings. So the files in b
look like they did in a
— they were dummy merged.
If you now make a new change on default
that you want to promote to UAT, you'll work with:
UAT: ... x --- y
\
default: ..... a --- b --- c
The merge is between y
and c
. It's a degenerate merge where the common ancestor is y
itself. This means that all changes between b
and c
will "win" in the three-way merge. The table for how hunks are merged in a three-way merge is:
ancestor local other -> merge
old old old old (nobody changed the hunk)
old old new new (they changed the hunk)
old new old new (you changed the hunk)
old new new new (hunk was cherry picked onto both branches)
old foo bar <!> (conflict, both changed hunk but differently)
Note that the merge result doesn't depend on the "direction" of the merge: the table is symmetric with regard to the local
and other
columns. Here, both ancestor
and local
is y
, and other
is c
. So the table becomes:
ancestor local other -> merge
old old new new (they changed the hunk)
You can see that the merge result always contains the new
change that was made in c
.
It's not important that the merge was degenerate. Assuming you have a new commit on UAT and that this commit doesn't touch the config strings, then you'll get the same behavior when you merge (in either direction, merges are symmetric).
The normal solution to this problem is to externalize the config strings. Put them somewhere outside of version control — environment variables, an unversioned config file, etc. If you can, then put a config file under version control as a template. You then create an unversioned config file for the UAT branch that includes the version controlled config file. You override settings as needed in this unversioned config file.