GitFlow: How to maintain previous releases?
Asked Answered
L

1

8

I am currently working on a workflow for my team. A suggestion we received was to use the GitFlow scheme. This scheme can be put on a chart as follow:

gitflow

However, I have one question about how to manage a specific case. Because of our activities, we have to maintain previous versions that our customer may still be using and does not want to update for various reasons.

In the GitFlow scheme, the trunk is supposed to be where the releases happens. A commit in the trunk is a potentially ship-able product and should receive a version tag.

So ... how can I go back in time, produce a fix for an older version and merge it back in the trunk in order to produce that release ?

GitFlow hotfix on released branch

An another question if I do not want that fix to be brought back in the trunk ?

It seems to me that this workflow is more adapted to software that continually pushes new versions to their customers, such as mobile apps, but not industrial products, even if they are built from a CI. But maybe I am missing something here, hence my question

Lashandralashar answered 26/10, 2021 at 15:27 Comment(2)
Git flow isn't designed for maintaining multiple versions in parallel. Have a look at e.g. softwareengineering.stackexchange.com/q/270321/110531.Monkhmer
@Monkhmer The creator of Git Flow disagrees with you, as he explicitly points out in his recent Note of reflection: "If, however, you are building software that is explicitly versioned, or if you need to support multiple versions of your software in the wild, then git-flow may still be as good of a fit to your team as it has been to people in the last 10 years. In that case, please read on."Impervious
I
5

Let's break apart your question into two parts:

how can I go back in time, [to] produce a fix for an older version ?

Your question mark in your second diagram is exactly right for this. Simply find the tag of the release you wish to modify, branch off of it (perhaps naming it something like hotfix/1.1.1), and commit your new changes. Then tag that "release".

For your second half of the question:

how can I ... merge it back in the trunk ?

And especially what if:

I do not want that fix to be brought back in the trunk ?

If you do wish to integrate that hotfix into trunk, it's easy- just merge it in (and if you have conflicts resolve them as you normally would).

If you don't wish to integrate that hotfix into trunk, you have some options:

  1. Keep your hotfix/1.1.1 around indefinitely. Branches are super cheap and this is a valid strategy that many companies use. (In fact many companies do away with the master branch altogether in a Git-Flow-Like strategy and just keep their release/ branches around indefinitely.) If you go this route you might someday have many remote branches, in which case I would recommend using the pseudo directory slash character (/) in your branch name as suggested with hotfix/1.1.1. Many Git clients enable you to roll up your branches by pseudo directory so you don't have to look at hundreds of branches that don't interest you (by collapsing the hotfix/ directory in the view.)
  2. My personal preference is not to keep lots of hotfix branches around forever, so instead you can get a little fancy and merge the hotfix branch back into trunk, but tell Git to ignore the change. After doing this you can delete the hotfix branch since all the information is contained in the new tagged commit in trunk.

Here's how to merge a branch without taking the changes:

git fetch
git branch -D main # in case you have an old copy of it
git switch main # now you should be up to date with origin/main
git merge --strategy=ours hotfix/1.1.1 # bring in commits without their changes!

Note the merge with strategy ours has no effect on the working copy. It's sole purpose is to bring the commit(s) from the hotfix branch in so that you don't need to maintain the hotfix branch anymore; you can simply delete it at this point.

Tip: Please be kind and use a descriptive commit message explaining that you did this and why!

You didn't ask this, but from my experience it's bound to come up eventually:

What if I want to integrate some of changes from the hotfix and not others?

That's a fantastic question! There are multiple ways to skin this cat, and before I learned about merging with the ours strategy, I would simply do the merge with the --no-commit flag, manually undo the stuff I didn't want to keep, and then commit the merge. The downside of this is that you are at the mercy of trusting that the merge commit was done correctly, and it's potentially hard(er) to troubleshoot. If you go this route, a descriptive commit message explaining what you did and why is important here.

My current preferred way of handling this is to split up the hotfix changes into 2 parts (typically 2 commits but it could be more). Make sure all the commits you want to integrate are first on the hotfix branch, and then the commits you don't wish to integrate come later. (Most likely you can use rebase -i to re-order them if needed after the fact, as long as it's before you tag it and release it.) The next steps are pretty straight forward:

git fetch
git switch -c merge-hotfix-into-main origin/main --no-track # create a temp branch
git merge <last-commit-you-want-to-integrate> # take in commits and changes
git merge --strategy=ours hotfix/1.1.1 # bring in remaining commits without changes
git branch -D main # in case you have an old copy of it
git switch main #
git merge merge-hotfix-into-main --no-ff

Note, the temporary branch merge-hotfix-into-main isn't actually needed here, but to stay with the spirit of --no-ff merges into main as defined by Git Flow, every first parent commit into main should represent a release, and that wouldn't be true unless the temp branch and it's 2 merge commits get brought in with a single merge commit on main.

Side Note: This is a minor point, but your first diagram appears to be violating one Git Flow principle, mainly, that tagged releases aren't making their way back to develop quick enough. Typically you'd have your blue dots pointing back to develop right away. You can see 3 blue dot releases that aren't in develop yet.

Impervious answered 26/10, 2021 at 18:2 Comment(8)
Side note: not Git Flow, but related to fixing old bugs: Stop cherry-picking, start merging.Courthouse
@Courthouse oh wow. I'm happy to know that through day to day experience I organically landed on what Raymond Chen proposes for merging back changes you wish to discard. The last article with the VSTS response is my favorite. And I suppose they would agree with me that if you're using -s ours you better document exactly why you are doing it in the commit message.Impervious
In Git Flow, I also organically landed on trying to avoid cherry-picking whenever possible. Nowadays the only time I accept it in Git-Flow repos under my control, is when someone accidentally completed their must have bug fix PR into develop instead of release or hotfix. Well, either accidentally, or Business changed their mind and upped its priority to "this release", after the fact.Impervious
Thank you for your long and detailed answer. I do see your point, however, in the light of this, I think it is preferable to go to a Feature Branch workflow. As I see it the point of GitFlow is to release from a single branch, if I start diverging from that base principle, I should assume it completely and go to a Feature Branch workflowLashandralashar
@Zangdar You're welcome! And I agree that the majority of the features contained in Git Flow exist for the purposes of the upcoming release. I think hotfix-ing older releases works well in Git Flow as I described in the answer, but regular active development on older releases might need some tweaking; perhaps maintaining prior release branches would be a good way to go there.Impervious
@Zangdar would you mind providing a little more detail about "Feature Branch workflow"? I always thought of that as just a fancy name for "Not trunk based development (TBD)", e.g. at a minimum you have main and some feature branches. If that's all it is, I think it's a subset of most popular branching strategies outside of TBD.Impervious
Here you are: atlassian.com/git/tutorials/comparing-workflows/… it is actually different than gitflow. Personally, I strip off the development branch, it adds nothing since the main is not the releasable branch.Lashandralashar
@Zangdar OK, that's what I was thinking it was. Back in 2005 and 2006 when Git was getting more popular, some people were all sharing master and other people said, let's use "feature (or topic) branches" instead of just sharing master. So they called that the "feature branch workflow". In other words, it's just "not TBD". Pretty much all of the popular branching strategies today (besides TBD) assume "feature branches" are being used. That "Feature Branch Workflow" I think today is more commonly thought of as (the Original) "GitHub Flow". Not to be confused with the current GitHub flow!Impervious

© 2022 - 2024 — McMap. All rights reserved.