2

For a project, say I have some release branches:

release/1.2
release/1.1
release/1.0

These release branches are based on the minor version. Because they keep being supported, each of them will be at a different patch version, stored somewhere in some build configuration file (gradle in my case). For example:

release/1.2
  build.gradle contains "version 1.2.1"
release/1.1
  build.gradle contains "version 1.1.4"
release/1.0
  build.gradle contains "version 1.0.7"

Now, suppose I fix a bug in branch release/1.0. Then I'd like to merge this branch to the next two, to propagate the fix. In general, this would work quite smoothly.

However, when fixing the bug in release/1.0 I would also want to bump its patch version, from 1.0.7 to 1.0.8, changing the file build.gradle to contain "version 1.0.8". But if I do that, the merge into the next release branches will create a conflict on that file.

Obviously there must be a better way to support my initial intentions. What are the best practices in this case?

One way I could think of is to not store the full version in a file, but only use git tags, and then have gradle (or any other build tool) obtain the full version from the git tag. One major disadvantage of this approach is that the build would fail on a sourcebase that is exported from git.

cornuz
  • 2,678
  • 18
  • 35

1 Answers1

1

Two possible solutions come to mind:

Cherry-picking

I have found that instead of merging, git cherry-pick works a lot better. With merging, you're running into the issue you are describing, and the version number might only be one instance of this. As the branches diverge further, you will find other conflicts that will not be easy to resolve. Since merging will always try to merge from the point where the branches were created, in many cases, far too many changes are pulled in.

With cherry-picking, you can migrate individual commits from one branch to another one. This works a lot better, since you can pick and choose which parts you want to migrate.

git cherry-pick 1234567

This will take the commit identified by the mentioned hash (it can be on any branch, in your case on release/1.0) and apply the commit on your current branch. It will just include the changes from this one commit, nothing else.

For me, this works a lot better than merging between support branches, since I can just take the parts that I want to fix, and does not include any other changes from previous or unrelated commits.

Git Attributes

If cherry-picking is not what you're looking for, you can use Git Attributes to define a merge-strategy for a specific file or a set of files.

See here for more details.

It lets you define an attribute like the following, where for the database.xml file, always our side is used when merging, disallowing any incoming changes during a merge for this file:

database.xml merge=ours

You would define the above in a .gitattributes file in your repo.

In your case, you would probably use something like

build.gradle merge=ours
nwinkler
  • 52,665
  • 21
  • 154
  • 168
  • Thanks @nwinkler. I see your point, though I still struggle to go for cherry-pick. I guess it also depends, as you say, on how much the branches diverge. In a setting where they don't diverge much, and they add up to the previous ones, I would see merge as more appropriate. There are also many posts about how cherry-pick should never be used in the first place. Perhaps, as always, the truth is in the middle. I do use cherry-pick but only really for a few specific cases. I would love a solution based on merge, even if it means to realize I'm using the wrong branching model. – cornuz Jul 31 '15 at 08:40
  • Fair enough! You might find an answer to this here: http://stackoverflow.com/questions/15232000/git-ignore-files-during-merge – nwinkler Jul 31 '15 at 09:59
  • Thanks to this link I found about git attributes, which may be the solution in my case. If you update your answer by adding this as another possible solution, I'll accept it. – cornuz Jul 31 '15 at 12:04