Skip to content

Auto-generate patch version with every commit to master. #205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MicahZoltu opened this issue Jul 5, 2014 · 20 comments
Closed

Auto-generate patch version with every commit to master. #205

MicahZoltu opened this issue Jul 5, 2014 · 20 comments

Comments

@MicahZoltu
Copy link

I am new to GitVersion so this may already be possible, but if so I couldn't figure out how.

I use the GitHub Flow style workflow meaning any commit in master could be a release and a build server will automatically deploy when things go green. I do not want to have to tag every time I commit, nor do I want to have to setup a build script that tags every commit (I would end up with a needless number of tags). I want every commit (and therefore every build) to have a unique file version number.

The way I would like to achieve these goals is by only tagging major.minor versions and having the patch version be the commit count since the most recent major.minor tag.

Example:

commit number tag version number
1 v1.0 1.0.0
2 1.0.1
3 1.0.2
4 1.0.3
5 v1.1 1.1.0
6 1.1.1
7 1.1.2
8 v2.0 2.0.0
9 2.0.1
10 2.0.2

The key here is that patch versions are super common (every commit ends up being a patch version) and I don't want to have to do any work to release patch commits. Minor revisions are less common and I don't mind having to do some work to get them versioned.

The one caveat is that the commit tagged v#.# should generate a build of that number. Unfortunately, you can't tag until after you commit which means there is a race condition between getting the tag onto master and the build server picking up the build and committing to a version. It is possible that GitVersion has already solved this problem with the nextversion.txt, I don't fully understand how that works yet though.

@MicahZoltu
Copy link
Author

A potential solution to the race condition of tagging vs committing:

If the HEAD commit message contains a version number (specified with some sort of convention like gv:2.0) then that build will be of that version. I could then setup my build server to tag that commit when it builds so the commits that come after will be able to match that version.

Thinking more on it, I actually would prefer this over manually tagging since at the time I am writing the commit/PR message I generally have a pretty good idea of whether something is breaking, non-breaking or bug fix. In the case of bug-fix I do nothing, in the case of a breaking or non-breaking feature I can simply put some magic string in my commit message (gv:2.1)

@JakeGinnivan
Copy link
Contributor

The commit message version bump you suggest is actually the same functionality as nextversion.txt. I think we have an issue already for this to allow a commit message version bump.

The thing is tags are used to mark a release, so if I download a particular version of your NuGet library I can use tags to see the corresponding source. We don't suggest using tags to bump the version.

To be honest I have not thought much about the continuous deployment scenarios with GitVersion. It is more geared towards continuous delivery.
Will give it some thought.

Sent from my Windows Phone


From: Micah Zoltumailto:[email protected]
Sent: ý7/ý5/ý2014 9:31 PM
To: Particular/GitVersionmailto:[email protected]
Subject: Re: [GitVersion] Auto-generate patch version with every commit to master. (#205)

A potential solution to the race condition of tagging vs committing:

If the HEAD commit message contains a version number (specified with some sort of convention like gv:2.0) then that build will be of that version. I could then setup my build server to tag that commit when it builds so the commits that come after will be able to match that version.

Thinking more on it, I actually would prefer this over manually tagging since at the time I am writing the commit/PR message I generally have a pretty good idea of whether something is breaking, non-breaking or bug fix. In the case of bug-fix I do nothing, in the case of a breaking or non-breaking feature I can simply put some magic string in my commit message (gv:2.1)


Reply to this email directly or view it on GitHubhttps://github.com//issues/205#issuecomment-48095774.

@MicahZoltu
Copy link
Author

So using GitVersion, could I use nextversion.txt to the desired major.minor version and have GitVersion automatically set the patch version to be the number of commits since that file has changed? This of course would require that the file only changes when the version changes, and not for other reasons like white space or formatting reasons.

@robdmoore
Copy link

If you are using continuous delivery then every commit could be released, but not necessarily hence why it doesn't increment the patch for every commit.

If you are doing continuous deployment and release every commit then you need to tag very commit since it's a release. Then your desired behaviour will result. The tag should be a semver of major.minor.patch, not just major.minor.

As jake said, having the version number in the commit is fairly pointless since it's the same functionality as nextversion.txt. However, I think it would be useful to have the ability to mark major or minor bumps via something like gv:breaking and gv:feature or whatever, but this has been discussed elsewhere (#137). That way you can leave the version calculation to gitversion and also allow for multiple breaking changes before you release and only one version bump to result (unless using continuous deployment of course).

@SimonCropp
Copy link
Contributor

doesnt "changing the patch number on every commit" go against semver?

@robdmoore
Copy link

It does unless you release every commit (in reality it wouldn't be every commit though - it would be every batch of commits that gets pushed and processed by the build server which might be 1 or more than 1).

@MicahZoltu
Copy link
Author

Following something like the GitHub Flow model, every commit that hits master is eligible for release. Taken to the next level, there might not even be any human intervention between commit/merge to master and deploy, only a serious of automated validations. Because of this, you don't know what is going to be released until after the last test has run and the binaries are about to be pushed out.

Perhaps I am misunderstanding something, but it seems like that leaves you with two options. Optimistically version every commit into master (what I am suggesting), or change the version on an assembly after it has gone through build validation but before you release.

The second option seems like a very bad idea to me because you end up running your suite of tests against a different binary than the one that ultimately gets released. Sure, only changing the version number is a pretty minor change but it isn't hard to contrive a scenario in which a test would pass on version 1.2.3 but fail on version 1.2.4. e.g.: if you have a test that ensures something like all packages in a suite have matching versions.

That being said, perhaps GitVersion isn't the right tool for the job? Writing a tool that does the kind of versioning I have described wouldn't be terribly difficult, and the idea of the major.minor version coming from a file is growing on me.

@robdmoore
Copy link

On the contrary this is exactly what GitVersion does allow you to do.

The patch number will auto-increment (unless you specify a major or minor change using NextVersion.txt or another versioning strategy - e.g. possibly in the future the aforementioned commit tags) after you tag a release. It will keep that version number going (with increasing numbers to semver metadata to create unique build numbers e.g. 1.2.1+1 and then the next commit 1.2.1+2) until such a time as your release happens (manual or automated) and you tag the released commit (with 1.2.1 in this case). The next commit that gets built will automatically have 1.2.2+x.

This way we've kept to semver rules (only incremented the version for a release), but also built the correct version into all of our assemblies so we don't have to rebuild (and thus are compatible with continuous delivery).

@robdmoore
Copy link

Oh any when I say "you tag the released commit" - that would obviously be an automated process...

@MicahZoltu
Copy link
Author

Ah, so perhaps I am just misunderstanding GitVersion.

Is the theory that before the build is kicked off, the build server would generate a tag based on the metadata? So if v3.2.1 is tagged in my repo, the build server would see a new commit hit master, kick off the build/test/deploy pipeline, and as a first step tag the commit with v3.2.2 (because 3.2.1+1 == 3.2.2). Then when it went to actually build (compile), it would pick up the v3.2.2 tag (which was just created) and version the assembly as such.

If the above accurately describes the workflow, my suggestion changes subtly. Taking GitHub.com as an example (http://scottchacon.com/2011/08/31/github-flow.html), at a rate of 24 commits a day your tags list very rapidly fills up with useless information (builds that only lived for minutes or hours). Rather than requiring a tag for each, it would be nice if I could avoid the requirement of tagging patch versions.

Currently, it appears GitVersion does FileVersion: 3.2.1 and Product version: 3.2.1+1. Would it be possible (perhaps through configuration) to instead just have it do FileVersion: 3.2.2 and Product version: 3.2.2? This would avoid having to generate a needlessly large number of tags when doing continuous deployment.

@robdmoore
Copy link

You should only tag a commit if you release that commit - not before a build is kicked off. That then informs GitVersion the commit was that particular version and it can calculate the next version based on that when there are further commits.

If you are releasing 24 times a day then yes, that means you have 24 tags in a day. Just because you have 24 commits a day doesn't mean that you will have 24 releases though (even if you are doing continuous deployment). For instance, you might merge a pull request that has 5 commits in it and those 6 commits (5 commits + merge commit) would constitute one new release and one tag on the merge commit for that release. Does that make more sense?

Looking at your suggestion - I think that directly conflicts with semver, which GitVersion is trying to implement so I doubt it would be changed to do that, but I also don't understand the value in that either - consider also what happens when you merge a 5 commit pull request - your version number will suddenly jump by 6 patch versions.

I should note I'm not a part of the core GitVersion team, but rather an interested party from the community.

@MicahZoltu
Copy link
Author

I appreciate the continued discussion on this topic, it seems that I am more ignorant than I thought as to how GitVersion (and perhaps semver) works. I think you are right that GitVersion (and perhaps semver as defined, if GitVersion aligns with it in this regard) aren't for me.

Re: "You should only tag a commit if you release that commit - not before a build is kicked off."

I am in the camp of, "only release the exact binary that you test". Since the version is part of the binary, you should not set the version on it after it has passed testing and is ready for release.

So, I have a tag v3.2.1 on master (which I released a while ago) with 3 commits on top of it. The build going through my build pipeline (whether I do continuous deployment or not) are all going to be versioned 3.2.1.0 on the binaries. They will have an attribute on them saying that they are 3.2.1+3, but the version of the binary (the thing baked into the assembly that the .NET Framework understands) is 3.2.1.0. I then decide (again, assuming no continuous deployment) that this commit is to be released, because it has passed all tests, so I tag that release in git as 3.2.2. However, the assembly for that build is version 3.2.1.

This leaves me with three options that I can see:

  1. Re-run everything so I get a new binary that is file version 3.2.2.0 that passes all of my tests.
  2. Modify the assembly to be file version 3.2.2.0, which goes against the "only release what you test".
  3. Release what I have tagged as v3.2.2.0 as file version 3.2.1.0, which could cause confusion.

It is my dislike of those three options that leads me to want every commit on master to have a unique and monotonically increasing version (by way of patch version going up every commit). Even considering traditional non-continuous deployment scenarios, I dislike all 3 options. I believe it is the first option that most people go with? Though, I can see people doing the second as well.

@MicahZoltu
Copy link
Author

Re: "consider also what happens when you merge a 5 commit pull request - your version number will suddenly jump by 6 patch versions."

I assumed the commit count was a shortest-path algorithm (correct me if I am wrong). If you always do a merge commit (never fast-forward) then the shortest path would always be one-commit per pull request. If you did a fast-forward merges then yes, your 5 commit pull request would jump by 5 versions. If you didn't do shortest path and instead did total commits and you did a merge-commit then yes, it would be 6.

Out of curiosity, is GitVersion in fact total commit count, not shortest path?

@JakeGinnivan
Copy link
Contributor

@Zoltu GitVersion will bump the patch for builds after a Tag. So it will be:

Tag 3.2.1, if you rebuild that commit you will still get 3.2.1, when you add a commit, GitVersion will build 3.2.2 for you (because 3.2.1 has already been released, and 3.2.2 is the next release).

3.2.2 can go through your tests, if everything passes, it is released. When the release is successful that commit should be tagged 3.2.2, then the next commit which is added will be built as 3.2.3. If you need to bump major/minor you use nextversion.txt.

Regarding commit counting, if you merge then those commits are on that branch, not just the merge commit. So yes, it always counts the commits which are merged in.

@MicahZoltu
Copy link
Author

Okay, I finally understand (it took me long enough). Thanks for seeing this thread through Jake and Rob!

@robdmoore
Copy link

:)

Is there any way we can change the documentation to make it clearer?

@MicahZoltu
Copy link
Author

I took a first stab here: https://github.com/Particular/GitVersion/wiki/MSBuild-Task-Usage

I'm fairly certain some of the information is wrong so I would suggest someone who is more familiar with GitVersion proof-read/edit it. As far as I could tell from the Wiki here, there isn't really any information on what magic strings you can tag with, what the format of the NextVersion.txt file is, or what happens when you tag a branch that isn't master with a magic tag. Such information would be useful for new users of the tool.

@robdmoore
Copy link

The information you put in is correct, but it's specific to GitHubFlowVersion so probably should appear on that wiki page? thoughts @JakeGinnivan

@JakeGinnivan
Copy link
Contributor

Yeah, probably needs to be added to https://github.com/Particular/GitVersion/wiki/GitHubFlow rather than the MSBuild task, which I think should be more about the actual usage of that task and how it works

@JakeGinnivan
Copy link
Contributor

Closing this issue, added a new issue to improve the doco: #209

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants