1

In a reasonable "merge-only to master" git workflow (e.g. gitflow) - all changes happen in branches, which in turn get merged (perhaps as part of a Pull Request) - how do I handle versioning?

For tagging, I easily can git tag the particular merge commit, no big deal.

But many app frameworks rely on a version file (e.g. package.json or gemspec or even custom files).

I see a few options:

  1. Modify the file as part of the branch. This isn't great, since you rarely know in advance which version will get merged in first, especially with a large team with many branches running in parallel.
  2. Modify the file after commit. This isn't great, since a- I now commit to master, and b- automated CI/CD will grab the previous commit and release it, but it has the old version number and c- with 2 commits to master for one release, it is possible to check out the wrong version; easy human error.
  3. Make the version file a template and auto-generate it from the git tag. This, too, isn't great, since local tooling will break on it (try running npm <anything> with an invalid package.json), and the repo no longer can stand on its own as an atomic unit.

Is there a reasonably standard way to do this when versioning is in a file that is part of the commit?

deitch
  • 14,019
  • 14
  • 68
  • 96

2 Answers2

1

You might employ a strategy that humans may contribute to master branch via merge-only, and only automated CI/CD (e.g. Jenkins) may change content of version file directly in master. The automated release process from CI/CD standpoint might look like this:

  1. pull master (master code freeze starts)
  2. run pre-release build (with old version)
  3. increment content of ver file and commit
  4. run release build with new release version (differs from #2 by content of ver file)
  5. push master to central repo (possibly with --force, if someone violated master code freeze)

As an addition, you may protect ver file from merge-to-master changes with .gitattributes in ver file directory with content verfile merge=ours (see here)

Community
  • 1
  • 1
IrLED
  • 438
  • 2
  • 5
  • Most of that I have, thanks @IrLED. The key to your suggestion is to have the versioning file changed only by CI/CD? The challenge to that is that there often is a lot more in there than just version. Think `package.json` or `Gemfile`. Much of it legitimately needs to change during normal dev process; just one field needs control. – deitch Dec 04 '16 at 19:06
  • >The key to your suggestion is to have the versioning file changed only by CI/CD? Yes, that's the point. To separate protected part from publicly available, you can run sort of pre-processing of `package.json` - inject a value from ver file. – IrLED Dec 04 '16 at 19:22
  • I need to think that through a bit. It would require some pretty brittle logic - per-file-type as well - to enable users to change everything but that one line. – deitch Dec 04 '16 at 19:40
  • in case of JSON - during pre-processing you deserialize the `package.json` in ruby (i assume you use it, by mentioning `Gemfile`), unconditionally overwrite/add `"version" : "1.0.0"` in that structure and serialize it back => users are free to change `package.json` how they want, but during the release the field "version" will have the value from protected ver.file – IrLED Dec 04 '16 at 19:56
  • It is an interesting approach. I am surprised I have not seen some sort of large-scale solution to this given the popularity of master-merge-only git flows. – deitch Dec 05 '16 at 06:35
1

It sounds like what want is a template version file in the repository that then gets built into the actual version file as part of the normal build system with info extracted from the repository.

I would suggest Autorevision to get the version info from the repository into form that is easy use to do this.

dak180
  • 71
  • 1
  • 5
  • Similar to @IrLED's approach, with specific tool, thanks. I think I will try some combination of the two. – deitch Dec 21 '16 at 04:49