When to drop support for deprecations in git-flow / semantic versioning - workflow

We work by the git-flow workflow and we stick to semantic versioning. Today we discussed how to handle deprecations. Two questions have arisen:
A. Semver: Is it ok to gracefully deprecate a feature in a minor release (e.g. v1.12.0)?
"Gracefully" means: The feature is still supported but a warning is shown in development environment. Support will be removed with a major release (in case of v1.12.0 with v2.0.0 or a subsequent major release).
B. Git-flow: How do you properly drop support of a deprecated feature?
Given we want to drop support for a feature in v3.0.0 while the last 2.x-release is v2.14.0. So 2.14.0 must support the feature while 3.0.0 must drop support for the feature, as any feature supported in 3.0.0 cannot be dropped before 4.0.0.
Subsequently we must remove the feature in the release/3.0.0 branch. But according to git-flow, a release-branch should only accept bug fixes.
Any advice highly appreciated!

tl;dr: One way to achieve this is to simply remove the feature on develop after the last 2.X release branch is made. Or feature flag the removal, and disable it on the first 3.X release branch. If you can't do either of those for some reason, it's still OK to do it on release.
Details:
Usually you can treat dropping this feature the same way you would treat adding a new big feature by simply merging it into develop. The only difference is that you need to make sure you get the timing right such that you don't complete the code removing the feature into develop until the last 2.X release branch is created. The next release branch that comes off of develop will have the code and will be the 3.X release. If the issue is that you don't know for certain when the last 2.X release will be, you could either wait until you do know and then merge the removal code into develop, or, consider feature flagging the removal with a config change. Then your change on the release branch whenever you create the 3.X version would simply be toggling the config.
That being said, perhaps ultimately it doesn't matter anyway:
But according to git-flow, a release-branch should only accept bug fixes.
Note there is no such thing as a Git Flow Authority which dictates what you must do. There is a popular standard Git Flow, but here I use the word "standard" to just mean "original" version that many companies use as a guideline. It is not "the" standard, as no such standard exists. I think the particular text you're referring to regarding release branches (emphasis mine):
This new branch may exist there for a while, until the release may be rolled out definitely. During that time, bug fixes may be applied in this branch (rather than on the develop branch). Adding large new features here is strictly prohibited. They must be merged into develop, and therefore, wait for the next big release.
Note even "strictly prohibited" is a (strongly) suggested best practice. There are no Git Flow Gods that will strike you down if you ever violate this rule. Besides, in your case, it could be easily argued that removing a deprecated feature on the release branch is not considered "adding a large new feature". (Even if we ignore the distinction between add/remove and new/old, perhaps the feature being removed is not "large".) Regardless, sometimes new large features do get added to a release branch, for a variety of reasons. This may violate best practices, but in the real world it's not always possible to follow best practice 100% of the time. Think of Git Flow as a guideline to work in, when it makes sense to do so. Note that Vincent Driessen specifically points out in the Note of Reflection that he didn't intend for Git Flow to become "dogma or panacea".

Related

Release control & issue tracking with Github

Based on my SO post I've been using Github as our VCS and with the help of the windows Github tool it's been great to handle those basic operations. Yet for merge like operations, I've to get back to Gitbash (SO Post) but thats ok.
So, the source code level VCS is in place. Now, we want to take a step
forward and use its simple issue-tracker to have "release control". For us,
this means being able to track each stable build (it can be a new
feature or bug fix, etc..) The idea is to create issues, tie them to a
milestone and use Github commit comments to close the issue and mark
it as a stable release/build. Where does tagging come in picture?
I've learned that we shud have a "development" branch for ongoing changes and periodically merged with the master (i.e. each stable build).
Is this the right way? We need to be able to go back to release / build 1.0 from 1.1 - sort of rollback just in case its required anytime in future (is this possible? how?) Is Github suffie or do we need to use some external tools as well?
Please share your experience and suggestions.
As I wait for other expert comments, I'd like to share a model that I've come across and seems great!
A successful Git branching model (SO Post)
To summarize, here is how I can address my basic needs (and scale it as and when required) -
Initially maintain two branches "master" and "development"
Master should always have a stable version and development has an ongoing source (might not be stable)
In the future, if we need to fix a bug after release, we can create a hotfix branch and when stable merge it with master/development
A good thing I found is that I can maintain stable releases in form of tags (i.e. new tag for each new version)
Eventually, master branch will be merged with development as we proceed with each stable version
There's a lot more that can be handled with the above model but I see my initial concerns addressed. Any better suggestions?

Proper usage of Tags in SCM

My co-workers and I are having an argument over the value and usage of Tags in release/SCM systems. We're looking to the StackOverflow community to put in their thoughts to help us resolve the issue.
One side claims that Tags are a valuable addition to release management. An example of their use: we do a Maven release, which makes a new Tag (call it 1.0) which is code snapshot used for this release. This Tag should be a READONLY branch. When a bug needs to be fixed we can make a copy of the Tag into a new Branch (call it 1.1). Bug fixes go there. These fixes may be merged back into Trunk so that the main dev branch gets the bug fixes. Finally, 1.1 is released and a Tag 1.1 is automatically created. This cycle continues. The main benefit here of the Tag is that if you ever need to re-release version 1.0 for any reason, you can just release the Tag 1.0 with the confidence that it's never been altered by anyone. Also, saying "Release Tag 1.0" is cleaner than saying "Release revision 1 of branch 1.0 which is the original 1.0 without the fixes".
The other side claims that Tags aren't providing any valuable benefit, especially in a system like Subversion with global revisions, which act like a Tag in CVS. Plus, Subversion only gives a warning when committing to a Tag; it doesn't actually stop it. Their method is developing in Trunk and upon release you'd make a Branch called 1.0. You'd continue bug fixes in Trunk and if you needed to re-release those bug fixes to production, you'd merge them into 1.0 Branch and re-release 1.0. At some point, perhaps after major fixes or features in Trunk, you'd release and make Branch 1.1. Cycle continues. If you ever need to release the original 1.0 version, you'd have to check out Branch 1.0 revision 1.
Clearly both methods work. I'd like to hear the community's thoughts on which method is preferred and why.
Edit: I'm a little worried that the "best" way depends on the underlying SCM system. Either settle on Subversion for answers or if possible keep it SCM agnostic.
From an SCM agnostic point of view, a tag is very different from a revision.
Both may be implemented in the same way, both represents a "time line", but their goal is different:
a tag represent an immutable state where all files are referenced by a unique id. It is a name representing many things but mainly a stable state, ...)
a revision represent a commit transaction (not all SCM have those, especially the old ones with a 'file-by-file approach'). All commits do not represent a "stable" state (as in "compile" or "execute" successfully). They are just a new element of the global history.
The problem with SVN is that revision, tag and branches are all implemented the same.
But I would still prefer the option where a tag is used as a "read-only" branch.
In my opinion tags are useful. There will be times at some point in the life of the project that you come across a bug or a change and you want to know if it was there in a previous release. There will be reasons to compare code from one release to another to measure efficiencies both in performance and actually the development of the code.
Sure, there is a chance you can screw it up, but it can always be undone. There really is no reason not to, and there are several reasons why it might be useful in the future. To me its a no-brainer.
I agree that you should also be using branches and doing your development there, but anytime you actually release something, make a tag out of it.
Yes, you want to use tags.
Think of a tag as just a label or a name for a particular revision. It is very helpful in my experience to tag important milestones in a project, whether it's for production release or even for interim QA releases. You often will want to go back in time and see the source code for a particular release.
If you branch upon release, you can always figure out which revision was released to production, but this is kind of a pain compared to just looking at a tag. If you don't use release branches then it will be easy to lose track of which revision was used to create a particular build.
The problem with svn is that it blurs the distinction between tags and branches. Anyone can always commit to a tag, so it's not guaranteed to be fixed/immutable. In other VCS like PVCS, a "tag" is unchangeable. You can adopt a team convention to prevent commits to tags, or even maybe use commit hooks to prevent commits to tags.
We use tags (labels) when creating new baselines. We do it once a week, but some teams do it even several times a day.
The point (for us) is always making sure the new baseline is stable: so it's not just a build, is a build that passes the entire testsuite, several hours of automated tests plus potentially manual exploratory ones too.
Then the baseline is used as starting point for all tasks during the next iteration: every new task is a new branch starting from the baseline, which is known to be stable so whatever is broken in the task should be easy to trace inside the task itself.
Normally we only put tags (labels) on the main branch (or trunk or master depending on your SCM flavour) which is the integration point for all the other branches.
When we release an official product we create a "release branch for it" so it will only receive fixes while new development stays on "main". Then these "maintenance branches" (hopefully only one or two at a time) can be tagged too.
I like to think about tags as "just a fancy name for a revision". I've always thought about them that way, and IIRC in mercurial they are just that. In subversion however, as you say, they indeed are (cheap) copies of trunk/* to tags/fancy-name/
Honestly, I'd combine the two strategies for optimal results: tag and branch upon release. Your tag is called 1.0.0, branch 1.0-MAINT. Bugfixes go into branches, and bugfix releases are tags again (1.0.1 may by a tag intended to alias 1.0-MAINT at a certain point.)
Do not forget however that tags and branches in subversion are actually the same thing: cheap copies. The only difference between them is the semantics you/your team attributes to them, so it pretty much boils down to getting people to agree on one particualr method and stick to that (might be enforced on the server, eg disallowing commits in tags/ except for release coordinators etc.)
The problem I see though with the second approach is: how are you going to make an easy distinction between software in the field if you re-release 1.0? That means that you may have a 1.0 and another 1.0 actually referring to a different code base... .
Immutable snapshots of a project's source code (and executable) are invaluable for doing testing of any kind, whether structured testing or field usage. For structured testing, you're going to be creating data that might be referenced months or years in the future. Anytime you revisit that data, Murphy's law says you'll need to know what code it comes from and unless you went to the trouble of citing a particular snapshot of the source code, it will be impossible to tell with confidence what source code corresponded to that test data.
I can't tell you how many times someone's come to me and said "This microcontroller code's not working, can you help?" and I ask them, "What version are you using?" and they say "I'm not sure" because they're not doing good release management (at the very least putting a sticker on the device, better to put versioning info in EEPROM that can be queried in realtime). >:(
In SVN, the technical difference between using a tag and tracking a revision is nil. I find myself minimizing tag use based on how SVN's implementation is simply a cheap copy and clutters up your "structure space".
The real difference comes when communicating a particular baseline to a large team of developers. Revision tracking brings an extra layer of abstraction that can become a source of errors. And as we're all aware, when you're dealing with 50+ developers, any source of error will become an area of confusion and wasted time. A verbose tag can eliminate that confusion and remove any doubt as to what a baseline's purpose is.
I'd combine both approaches. Whenever you make a release, tag it. Tags should never change, so the presence of a "1.0.0" tag is an indicator that you shouldn't be trying to release anything else as 1.0.0.
At the same time, when it came time to do 1.0.0, I'd put it onto a 1.0 branch. So the flow is: branch trunk to 1.0, tag this new 1.0 as 1.0.0, and deploy. Then bug fixes can be done on the 1.0 branch (to avoid getting mixed up with any 1.1-targetted development that may already be on trunk now) and merged into trunk. Each release of the fixed 1.0 is tagged as 1.0.x from the 1.0 branch. This is basically the approach we use at work with Perforce, and that's very similar indeed to Subversion. (Reading through the replies, I think it's virtually identical to Vincent's recommendation)
As far as the comment about tags being redundant because you have revision numbers--- that's largely true, except that tags also specify a scope: i.e. which files in the repository are covered by the tag. You can reasonably ask someone to look at /svn/proj1/tag/1.0.0 and they are immediately looking at a coherent workspace. If you ask them to look at revision X, they have to first look at revision X to see that it was changing (say) /svn/proj1/trunk/Makefile and hence deduce that /svn/proj1/trunk/#X is what they should be looking at. What happens if revision X touched files in proj1 and proj2? Which is of course evil, but strictly speaking you should be saying /svn/proj1/trunk/#X. And where is the list of revision numbers stored? How do we know that 1.0.0 is revision X? It should IMHO be possible to determine that just from the repository.
In systems like Git, tags and branches are still basically the same thing (just references to the object database), but the convention is that tag refs don't change, and branch refs do (and preferably with a specific constraint on how they change). Perforce also has "labels" which are ways of grouping a set of file revisions together independently of a changelist; which is essentially a tag, but more confusing: historically we've used changelist numbers (equivalent to Subversion revision numbers) qualified with the name of the branch they should be on to identify versions. The two are almost identical any way, so here I guess TMTOWTDI.

Do you create a label/tag for a specific release/path or a branch?

If you have a version 1.0 of a product, or say 1.1 or even a patch, do you create a tag/label or a branch?
Eric Sink wrote a great series of articles about the ins and outs of version control. I'd suggest using those as a starting point.
Depends on the version control system. I'd branch for incompatible (major version number) changes, and tag for compatible (minor version number) changes. That leads to a whole discussion about what's compatible and what isn't, though...
Or, just use Subversion, where you'd normally use "svn copy" for either.
I usually don't branch but only label the releases. This way, I can branch later when the need arises. Since branches are so expensive in CVS, try to avoid them until you really need them. For all other VCS tools, branching is so cheap that you can do it as you need it, so no need for premature actions, either.
It depends a bit on the tool (version control system) you use, if it has sane branching and tagging.
In Git I would use tags such as v1.0, v1.1 to point to exact version (tags do not change), so if somebody would tell you that there is a bug in version 1.0, you would know exactly what it contains. If there would be a need for long-term maintenance, I would use branches such as maint-1.0 and maint-1.1 to gather maintenance bugfixes for past version, and from time to time tag new minor release such as v1.0.1, or v1.1.5.
HTH

Do you have any commit policies?

My boss announced yesterday a new commit policies for checkins into the repository. This policies are valid for commits into head/trunk and branches.
A commit message must have the following items:
Reason (Bug ID,Project ID, or non functional change)
Name of the reviewer
After the commit we also have to create a change blog entry in our CMS.
I'm not a big fan of this commit policies, because I don't normally need a reviewer when I am doing new or experimental stuff in a non-productive-branch.
Do you have any commit policies do you have to follow?
I think it is a good idea to change the productive-branch only due to a Bug Report, but commits into the development branches should be less restrictive.
Commit early and commit often.
We actually use /trunk as development and tags to branch different releases. Only structural intrusive changes go in /branches.
We actively use tags for production and acceptation releases, so we can go back in time easily. Anything committed in the trunk should only have a message describing what the commit changed or added briefly.
I'm not a big fan of using the message space to link with Bug ID's it still requires a lookup for the ID in which case you could also look it up in the bug tracking software and close it there, which to me is about the same effort.
Not to say i dont like any svn integration:
- We use more goodness of automated nant scripts to make releases which branches them in /tags
- svn props actually store our version numbers :p.
- hook scripts for email notification and message logging (great for copy pasting release notes).
We have a number of policies, which are enforced via an in-house plug-in to Visual Studio. We check that code compiles and that unit tests have be run successfully. At the moment we also check code coverage and issue warnings for code which doesn't have enough tests. We also do various consistency checks and verify that an appropriate task is present in our change management system in order to provide traceability for all changes.
The advantage of tool support is great, as it is not really up to people to respect the policies, but obviously there's a drawback as well as these checks take time to run. However, with many developers it is hard to enforce standards without proper tool support.
A reviewer seems pointless for the reasons you mentioned, because not everything needs to be reviewed by others.
In the past the only commit policy we had (where I used to work) was to include a comment indicating what you changed and why, but that's more common sense than anything else.
A common commit policy is to associate a bug ID to the commit to trunk as a justification. Sometimes, version control and bug tracking systems are configured to enforce this policy.
Our commit policy sounds a bit like yours, only we don't enforce it on task branches (where a task branch is like a developer's sandbox for experimenting).
Our commit comments must include either a change control ID (new feature, enhancement) or an issue ID (bug fix). You must also include a brief explanation as to why you made this change; version control tracks the who, what, when and where.
My commit message include a short describtion what i have implemented or changed in the classes.
The bug number and additional describtions i put in the commentation above the new code. IDs inside the commit messages we put when we merge changes into a tagged branche.
Every night a automatic build checks the different features and products too get sure that the code base is stabil.
But in the end i think you can not have too many describtions for new or changed classes but too many policies you have to do before a commit. The name of the reviewer is something which i would not put into the commit message.
Think about that you sometimes have to undestand your code which you have implemented 2 years ago. And then you are happy about commit messages which are not like "Update after debugging".
We have branches for every released major version of the software that is still actively supported. Checking into any of these branches requires a bug ID - this is enforced by scmbug, which will not only check that the comment is prefixed by the bug ID, but will also look up this bug in the bug database, ensure it is assigned to the committer, and potentially check other criteria (e.g. that the "fix in branch" field is the branch being committed to).
One of the products has more potential to fail in embarrasing ways, and checkins to this require not just a bug ID but a code review as well. However, the criteria for the code reviewing is handled in our bug database - we have custom fields for this and the bug cannot be accepted and closed until it has been reviewed. To me this works from a conceptual level - it's probably better to check code that is believed to work into the repository un-reviewed, then reopen the bug and change it if necessary rather than hold off on committing until you're sure it is ready for release.
Other than that, there's no explicit policy for the trunk (though of course the general tenets of checking in often without breaking the build, including good descriptive commit messages, checking in units of work atomically still apply).

Best practices, building trunk against trunk?

We have many projects that use a common base of shared components (dlls).
Currently the development build for each project links against dlls built from the trunk of the components. (ie trunk builds use the dlls from other trunk builds)
When we do a release build, we have a script that goes through the project files and replaces the trunk references to specific numbered versions of the components (that are built from a tagged branch)
I think this weakens the testing that we do during development because the project that I am actually working on is using diferent dlls to what the release build will be using. I would like to always develop against the numbered versions of the components and only ever update them when there is a specific need.
However others in the team argue that unless we develop against trunk (and update to the newer versions of the components with each release) we will have the problem that (a) our products will hardly ever update to the newer version of the components then (b) when we do need to update it will be a huge task because the component source/interfaces will have changed so much.
What practices do you follow, and why?
Edit: Sorry all, I have just realised I have confused things by mentioning that there are several main products sharing components - although they share the components they don't run on the same PCs. My concern relates to the fact the because the components are likely to change with each release of a product (even though there was no specific requirement to update the component) that testing would miss some subtle change that was done in a component and not related to the specific work being done on the product.
Hmm, I may be in a minority here, but this comes down to release management.
Developing against the trunk of a set of shared components means, by definition, that the components are a "moving target" -- a developer using those shared components won't necessarily know if a newly found defect or failure is due to the project code or the shared components, which leads to a loss of productivity, IMNSHO.
The "shared components" have a release cycle all their own. Give your other developers a break and fix the version of the shared components that the projects are going to use and use tags, labels or branches to identify the shared component release. On the next iteration for the projects, bump up to the latest "stable" or "production" build of the shared components.
There's another "smell" here, if you'll pardon the expression. Having "shared components" whose "source/interfaces will have changed so much" between project releases sounds like the components aren't so solid or shouldn't necessarily be shared.
See also the answer to this question Shared components throughout all projects, is there a better alternative than svn:externals?
You should have strong interfaces that rarely change, so changing versions shouldn't be that hard.
Separating the versions and working against specific versions will increase overhead when you need to change, but it should also encourage less interface changes overall, which will help in the long term.
We develop against multiple branches and trunk simultaneously and we have chosen to build and test each branch with the code we'll be pushing out to production. I don't think it is safe any other way.
Basically, if a developer is working on trunk, all they have to do is worry about building from trunk and committing code to trunk.
Any developer working on a branch needs to build and test off that branch (there are multiple projects all branched/tagged the same build/release). When they commit changes to that branch, they must also merge those individual changes into trunk.
We expect all developers to be familiar with SCM (SVN) and to be capable of maintaining multiple branches of code. As a team we handle major framework shifts or huge code changes to minimize troublesome merging.
Two things here. First, I think you're right; you want to build against the most current development versions, not against the old versions. If you haven't already, you will see a situation in which the build-for-release blows up and you have to do an all-nighter cleaning up the diffs.
I'm personally a fan of the "commit to trunk, release from branch" model anyway. All commits go to the trunk, overnight builds or CI builds are against the trunk, and people create branches freely. When you have a trunk that meets acceptance criteria, tag a release candidate, BUT KEEP MAKING UPDATES TO THE TRUNK. If you hae a long release cycle, then you might have changes for release n+1 being added to the trunk, but ideally you should just shorten your release cycle instead. If there are changes to the trunk that shouldn't be in the released version, AND you have a problem that requires changes, create a branch against the tagged version --- and make sure you merge any changes back to the trunk once you have an actual release.
We are using the scons building system, and have our own file in the root directory which specifies what version of each library we're going to use when building the application.
That reduces the need to change version names in several locations like you mentioned.
Whether (b) is a valid argument depends on how often your shared components change and by how much. If they change often in your workplace, it might be a valid that you are "forced" to develop off the newest version. Whether that in itself is a problem is a valid question.
However, from your side of things, I don't see how you can push code into production without it being tested against the shared components being used in production. Do you do a second test cycle against the release build? Do you just pray that nothing breaks? Frankly, (b) can be reversed in these cases to support your point of view: If the trunk is different enough from the most recent tagged branch, then that effort has to be made to ensure your app works properly with it.
If your shared components are tagged often enough, then your colleagues are probably right, and it's easier to manage the incremental changes from the most recent tag to the trunk than it is to manage the change from arbitrary version X (determined at the last build) to arbitrary version Y (determined when you choose to upgrade).