Imagine we use Gitflow where we have split a release branch from develop
that will eventually be merged into both main
and develop
.
On release
there are only quality improvements.
Most of these require a deployment to an integration stage, so their version in several pom.xml
(multi-module) and package.json
is updated and tagged on the release
branch.
On develop
there is regular (unstable) feature development for future releases, and the version has been set accordingly.
Occasionally the improvements from release
are merged back into develop
.
There we get merge conflicts, marked with an X in the following illustration.
main ----------------------o----
/
release o---o-----o-o-o
/ \ \ \
develop ----o---o---x--o--x-o-x----
^
we are here |
Example:
- On
release
the version number is1.0.0-SNAPSHOT
. - On
develop
the version number is1.1.0-SNAPSHOT
after branching off. - New features go into
develop
, the version number stays constant there. - The version in
release
is incremented (and tagged) occasionally to1.0.1
,1.0.2
,1.0.3
and so on. - Now of course there is a conflict when I want to merge version 1.0.x into 1.1.0 while the common ancestor is 1.0.0.
- (We fully understand what happens there, don't need explanation for that.)
$ git checkout develop
$ git merge --no-commit --no-ff release
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
...
Auto-merging client/package.json
CONFLICT (content): Merge conflict in client/package.json
Automatic merge failed; fix conflicts and then commit the result.
We are looking for ideas to handle this situation. Some research shows that this is not an uncommon problem, so I found several suggestions. Mostly it is said to just manually resolve the conflicts. But I am still eager to find a way that can be automated in a script. Maybe there is some Git magic to help? Maybe we started badly in the first place?
The following discussion brings a better image to it, where we are at "Only bugfixes!":
Approach 0 -- Do not do this?
Since our team started doing this kind of version increments and tagging, I've been unsure if this is a good practice. But it basically works, we defined the details of the workflows together, and our customer and partners and test team require us to deliver release candidates as if it were actual releases. When a version x.y.z has been tested successfully, it goes to productive environment unchanged and then release
is merged into main
. But the problem stays: As soon as a hotfix is made in main
and should be backported to develop
, we are going to get version conflicts again.
Approach 1 -- Cherry Picking?
Sorry, I won't do this. Too often I read that cherry picks are evil. And they would be against Gitflow.
- http://www.draconianoverlord.com/2013/09/07/no-cherry-picking.html
- Git - Is cherry-picking a bad practice if I want to have a consistent workflow?
- https://medium.com/@vitalishcharbin/danger-of-cherry-pick-42a56141577f
- Why does cherry-picking make the repo unstable?
Approach 2 -- Accept to resolve manually?
That is what we do now. The process is not automated. Every time the version number in release
is changed, the following merge gets a conflict that has to be manually resolved. We accept it but are unhappy with that.
Approach 3 -- Do not merge that often?
I guess that would be bad practice. We want to have the quality improvements merged to all our branches.
Approach 4 -- Use merge option --ours
or similar?
The problem is that automated "resolution" of merge conflicts is file-based, from what all I could find out, not line- or block-based.
We need to keep the version number from develop
, but other changes in those files pom.xml
or package.json
might be on either side and not to be overridden blindly, so these kind of conflicts we want to see and resolve manually.
I am open to any suggestions in this direction though!
Approach 5 -- Move version number to separate file?
This way we would reduce the conflicts to one single location where it can be trivially resolved using --ours
.
While it seems to be possible with newer Maven versions, I am not aware of an approch for package.json
to refer to an externally defined version number.
Has anyone made good experience with that and would recommend to go further this way?
Approach 6 -- Prepare and reset version in develop
?
I saw such behavior by jgitflow-maven-plugin
which is not maintained for over 6 years now. We could make a commit in develop
, writing the release
version into the files, then merge, and change the version back to the original one.
I dislike that there would be additional commits that have nothing to do with actual development, and I see no possiblity to clean up the Git history.
So this would be an interesting follow-up question: I know I can rebase/squash D into C, but I don't see how I can rebase/squash A or B into C. Does anyone else?
-----B---------
\
---A---C---D---
Approach 7 -- Prepare version in release
?
Similar to the previous approach, we could make a commit in release
, write the target version, then merge to develop
without conflict. We would then not need a revert commit in release
but could just move the branch pointer back with git reset --hard HEAD^
and/or simply not push it, so this preparation commit would be located "between" the two branches.
-----B-----------
\
B'
\
---A-----C---D---
The following article describes a similar thing using an intermediate branch (to fulfill the requirement for a pull request), but it is several manual steps that don't solve my challenge.
- https://medium.com/@jshvarts/dealing-with-conflicts-when-merging-release-to-develop-da289a572f0d
- https://www.reddit.com/r/git/comments/e7zwl6/dealing_with_conflicts_when_merging_release_to/
Approach 8 -- Prepare version without commit?
My favorite solution would be to just write the target version in local develop
without commit, then merge release
onto that... but git merge
does not allow this. I do not see any switch to override this behavior and ignore unmerged
error: Your local changes to the following files would be overwritten by merge:
client/package.json
...
pom.xml
Please commit your changes or stash them before you merge.
Aborting
Searching the web tells me to stash the local changes, but that is not an option of course.
Approach 9 -- Write program to resolve conflicts?
I play with the idea that these conflicts are well-structured and can even be fully predicted, so it should be possible to write a small shell script to grep/sed the conflicts in order to automatically resolve and commit the merge. But I hesitate to put large efforts here and hope for enlightenment by other people!