[HN Gopher] A note of reflection after 10 years of "A successful...
       ___________________________________________________________________
        
       A note of reflection after 10 years of "A successful Git branching
       model"
        
       Author : nilsandrey
       Score  : 78 points
       Date   : 2020-03-05 18:52 UTC (4 hours ago)
        
 (HTM) web link (nvie.com)
 (TXT) w3m dump (nvie.com)
        
       | mkchoi212 wrote:
       | So cool that something Linus Torvalds made to solve his own
       | problems, spread all around the world so quickly. I guess great
       | dev tools can only be made by great developers, who have been
       | through a lot of scenarios/problems themselves.
        
         | zwieback wrote:
         | What's interesting to me is that git does not seem like a
         | "great dev tool" when you first start using it, especially if
         | you're already used to another VCS. Right now I'm using SVN,
         | Perforce and git for different projects and I definitely like
         | git the most, but it took a while to get there. And it's not
         | the centralized vs. decentralized per se, like 99.9% of git
         | users I'm almost always within milliseconds of a central
         | server. The big change was to treat my development "as-if" I
         | was doing my own thing, decentralized, when in fact I'm not.
        
         | bmn__ wrote:
         | Don't neglect to give enough credit to BitKeeper, the DVCS some
         | kernel folks used before and whose design in broad strokes was
         | cloned by Linus.
        
       | yodsanklai wrote:
       | Reading the comments, I realize I'm a git neophyte (limited
       | experience working on some open source software, didn't know
       | "gitflow" was a thing) so excuse me for my naive question. But
       | what about this simple workflow. Developers submit PR on top of a
       | master branch (developer is in charge of rebasing, PR must pass
       | integration test). Administrator is in charge of merging,
       | maintains a linear history. Releases are just tags on master. Has
       | this workflow a name? anything wrong with it?
        
         | mugsie wrote:
         | "Trunk based development"
         | 
         | It is fine, unless you do a lot of back ports or bug fixes for
         | older releases, at which point the version branches are very
         | useful.
        
           | quicklime wrote:
           | Trunk based development, as described at
           | https://trunkbaseddevelopment.com/, can be used with release
           | branches, where bug fixes can be back ported to.
           | 
           | Are there any reasons at all for using git flow over trunk
           | based development with release branches? The latter seems far
           | simpler but just as flexible.
        
             | ivankolev wrote:
             | That works until you have to support lots of old versions.
        
               | quicklime wrote:
               | I don't understand why you think that. Can you explain
               | why having many release branches is harder in trunk based
               | development?
               | 
               | In a previous job, we would just cherry pick bug fix
               | commits over from master to all the active release
               | branches. It wasn't hard.
        
         | SideburnsOfDoom wrote:
         | https://trunkbaseddevelopment.com/
        
         | btilly wrote:
         | Here is what is wrong with it.
         | 
         | It will work fine 99% of the time. But when you get into
         | trouble (and a single merge done badly may cause trouble) there
         | is no way to recover it because you lost history. And trouble
         | is often of the form, "A month of my work went poof and nobody
         | noticed for weeks after."
         | 
         | Another pain point is that the Administrator becomes a
         | bottleneck. And when the Administrator runs into a conflict
         | they often have no context from which to sort it out.
         | 
         | But on the positive side, your history will be nice and linear.
         | Which makes tools like git-bisect very, very happy.
        
         | jimktrains2 wrote:
         | Sounds like GitHub Flow. https://githubflow.github.io/
         | 
         | As others have stated, this works well when there aren't
         | "releases" but once you have releases with versions and may
         | have to backport things, it starts to breakdown. For how most
         | web-based software is developed it seems to be a descent for.
        
         | kubanczyk wrote:
         | A year after you release v1.0.0 (which you say is a tag), a
         | customer reports a bug in it. They don't want a breaking
         | upgrade to v9.13.0. They want to pay for v1.0.1 (aka "hotfix").
         | 
         | But you can't open a PR against a tag v1.0.0. Hence you
         | discover that v1.0 should be a branch, and both v1.0.0 and
         | v1.0.1 tags. This way you can open a PR against v1.0 and easily
         | create v1.0.1, v1.0.2, etc.
         | 
         | Another problem. You are at "master" and approach v13.0.0. But
         | there are numerous bugs to fix before you release. Testing
         | takes >24 hours. You choose to work on bugs on a branch (v13.0)
         | this way master can proceed with new features and not be
         | feature-frozen for days or weeks.
         | 
         | Another problem. Your CI is deficient in that it allows merging
         | and cloning before it makes sure that previous merge produced
         | good product. Puny as it is, it is the current industry
         | standard. Thus your main branch becomes broken now and then. So
         | you call it "develop" and only merge it to "master" what you
         | are sure is a good product.
         | 
         | If these common situations don't apply to you - proceed as you
         | are. Do the simplest thing possible, but not simpler. What
         | you've described doesn't create any roadblock or dead end
         | street for the project.
        
           | deepersprout wrote:
           | > A year after you release v1.0.0 (which you say is a tag), a
           | customer reports a bug in it. They don't want a breaking
           | upgrade to v9.13.0. They want to pay for v1.0.1 (aka
           | "hotfix").
           | 
           | > But you can't open a PR against a tag v1.0.0. Hence you
           | discover that v1.0 should be a branch, and both v1.0.0 and
           | v1.0.1 tags. This way you can open a PR against v1.0 and
           | easily create v1.0.1, v1.0.2, etc.
           | 
           | So you could just `git checkout v1.0.0; git checkout -b
           | v1.0`, commit your hotfix and deploy v1.0.1.
           | 
           | > Another problem. You are at "master" and approach v13.0.0.
           | But there are numerous bugs to fix before you release.
           | Testing takes >24 hours. You choose to work on bugs on a
           | branch (v13.0) this way master can proceed with new features
           | and not be feature-frozen for days or weeks.
           | 
           | Or you could use topic branches for new features, and fix
           | bugs on master at the same time.
           | 
           | > Another problem. Your CI is deficient in that it allows
           | merging and cloning before it makes sure that previous merge
           | produced good product. Puny as it is, it is the current
           | industry standard. Thus your main branch becomes broken now
           | and then. So you call it "develop" and only merge it to
           | "master" what you are sure is a good product.
           | 
           | I don't understand your point here. Usually your CI builds a
           | branch, runs some tests on the compiled product and makes
           | sure the `master` branch is ok before deploying to staging or
           | production.
           | 
           | > If these common situations don't apply to you - proceed as
           | you are. Do the simplest thing possible, but not simpler.
           | What you've described doesn't create any roadblock or dead
           | end street for the project.
           | 
           | I think there are a lot of branching strategies for a reason.
           | Your use cases can be covered with other branching strategies
           | as well.
        
             | lolc wrote:
             | > Or you could use topic branches for new features, and fix
             | bugs on master at the same time.
             | 
             | One could but it's often very desirable to integrate
             | branches fast. If merging is delayed by a release there
             | will be stale branches to merge. The experience of merging
             | long branches scares people off of refactoring, because a
             | refactoring creates more conflicts the longer it stays
             | unmerged.
             | 
             | > I don't understand your point here. Usually your CI
             | builds a branch, runs some tests on the compiled product
             | and makes sure the `master` branch is ok before deploying
             | to staging or production.
             | 
             | As long as you have sequential merges there is no problem.
             | But when you merge into the main branch and it is ahead of
             | you (due to another merge) the build may become broken. You
             | can merge the other way first, sure. But if you want to
             | enforce this you need support from your infrastructure.
        
               | qznc wrote:
               | The only way to be sure: CI checks out master, merges the
               | feature branch, and tests that version. If successful,
               | push to origin. If the push fails (because a parallel
               | pushed happened in between) start from the beginning.
               | 
               | The challenge here is that pull request might be tested
               | again and again. It increases the CI load by some factor
               | for large projects.
        
             | kubanczyk wrote:
             | > `git checkout -b v1.0`, commit your hotfix and deploy
             | v1.0.1
             | 
             | And the code review happens where? You need to:
             | git checkout -b v1.0       git push       ask your
             | colleague for a code review of branch v1.0
             | 
             | Parent asked if they can only live with feature branches
             | and master. Branch v1.0 is neither.
             | 
             | > I don't understand your point here. Usually your CI
             | builds a branch, runs some tests on the compiled product
             | and makes sure the `master` branch is ok.
             | 
             | Gasp... You are right, you don't understand my point. You
             | show master to everyone before making sure it isn't broken?
        
         | snarfy wrote:
         | Please correct me if I'm wrong, but I believe this is the model
         | the Linux kernel uses.
        
         | deepersprout wrote:
         | Your model is called trunk based development and personally I
         | like it a lot. It keeps the history clean and is very easy to
         | use even for junior devs.
        
         | woodrowbarlow wrote:
         | the risk of this workflow is that PRs will languish for too
         | long, and the work required to rebase them when they're
         | actually needed will cause friction and mistakes. this will
         | often manifest when your software reaches a certain level of
         | maturity and you have established a release model that
         | distinguishes between a release that includes only bugfixes and
         | a release that introduces new features.
         | 
         | you definitely want to get your PRs merged in to _something_ as
         | soon as they are complete, to avoid bitrot. but just because
         | they're complete doesn't mean you want them included in the
         | next release.
        
           | dtech wrote:
           | > but just because they're complete doesn't mean you want
           | them included in the next release.
           | 
           | That's the crux. Continous Delivery means exactly that. You
           | want to release early, small and often. Trunk-based
           | development and having every PR that is merged to master be
           | deployed to production in a very short timeframe fits that
           | very well. That's very possible with a solid CI/CD pipeline,
           | good tests, and something that can be deployed often like a
           | web app.
           | 
           | If you don't do continuous delivery, trunk-based development
           | might be a less natural fit.
        
           | grovellogic wrote:
           | You can merge master/develop into your PR multiple times,
           | always keeping it up to date with the latest until until it
           | can be merged.
           | 
           | This is the magic of git, it allows multiple merges something
           | that wasn't possible in older systems.
        
             | ivankolev wrote:
             | That is what I do too. Combined with restriction on the
             | pull request so you can't merge it if it's behind the
             | branch you are merging onto.
        
       | umvi wrote:
       | I tried using Gitflow on our team, but there was too much
       | complexity for me. We ended up switching to Trunk Based
       | Development (TBD)[1] which I and my team found to be much
       | simpler.
       | 
       | [1] https://trunkbaseddevelopment.com/
        
         | Legion wrote:
         | Trunk based using short lived feature branches is the only
         | thing I've used that has made any sort of sense in terms of
         | value vs. complexity.
        
         | zoomablemind wrote:
         | Same here. Trunk based is easy to explain and enforce.
         | 
         | The only challenge we faced was maintaining patch releases.
         | Folding in fixes for common issues which were found in newer
         | releases sometimes involved more than just cherrypicking the
         | fix into a patch release for an older version.
         | 
         | This inevitably led to asking users to update to more up-to-
         | date versions. This further enforced the linear development
         | paradigm.
        
         | billti wrote:
         | I would love all the hours back I spent in discussions around
         | branching strategy, trying to keep complex models understood
         | across the team (and myself), dealing with painful merges and
         | flowing changes through, trying to figure out if a change is in
         | a branch already, etc..
         | 
         | It's so much simpler and more productive if everyone works in
         | master, with new features behind a flag if need be, with just
         | critical fixes ported to release branches.
         | 
         | There will always be arguments for why a more complicated
         | branch strategy needs to be introduced. Resist those arguments.
         | In my experience, the cost rarely pays for any benefits.
         | Writing good software is hard enough already.
        
         | wcarss wrote:
         | +1 to trunk based. There's obviously a lot there, but one of
         | the best bits is the idea that each release deserves a branch.
         | It makes hotfixes, ci/cd, and rollbacks all much simpler to
         | reason about.
        
         | alexbanks wrote:
         | I didn't know there was a name for this, but I've been doing it
         | for 2 years now and I don't think I could go back.
        
       | cjfd wrote:
       | It all depends on the situation. The simplest possible situation
       | of mostly just having a master branch also can work quite well.
       | When you have specialized testers that test a candidate release
       | you start to need release branches. Feature branches start being
       | necessary if changes are temoprarily incompatible with current
       | master. This should not be too common, though. In many cases one
       | can avoid feature branches by having feature switches that get
       | removed as soon as a feature is done. If one wants to or needs to
       | use feature branches they should be short-lived because one will
       | be creating a merge hell if this is not the case. The git flow
       | seems just too complicated for most cases. One comment already
       | notices that it is quite unclear why a separate development and
       | master branch are necessary.
        
       | edpichler wrote:
       | I love this branching model. I have being used in all projects
       | and teams I can. I use it even in projects where I work alone.
       | For me it is the ultimate branching model.
        
       | [deleted]
        
       | gulbrandr wrote:
       | Is this related to the "Please stop recommending Gitflow" [1]
       | article posted yesterday?
       | 
       | [1] https://news.ycombinator.com/item?id=22485489
        
         | [deleted]
        
         | sytse wrote:
         | Kind of, that article recommends making things less complex if
         | you do continuous delivery to a SaaS.
         | 
         | The update article mentions it was meant for versioned
         | software.
         | 
         | I tried to articulate the various levels of branching you need
         | in GitLab Flow
         | https://docs.gitlab.com/ee/topics/gitlab_flow.html The various
         | levels are: feature branches, production branches, environment
         | branches, and release branches.
        
       | debaserab2 wrote:
       | I've yet to work on a codebase that was so congested it required
       | such strong delineation between feature/hotfix/release but I can
       | see how it might be required at a certain size. I wonder what
       | that threshold is.
        
         | stickydink wrote:
         | It depends what you're working on. We have a fairly small team
         | (7 engineers) working on a reasonably complex app (many
         | features).
         | 
         | Our "features" take anything from 1 day to 3 weeks of effort,
         | and generally need to roll out as a whole. They are often
         | really upgrades of existing features, and the work to
         | continuously merge w/ feature flags, supporting both
         | flows/designs, is just not something we've felt was worth the
         | extra time.
         | 
         | We release on a 2 week cycle, the same day each time. We merge
         | our features into the develop branch as they are ready and safe
         | for production.
         | 
         | Our scheduled release day is Wednesday. The Thursday
         | beforehand, we branch from develop into a release/x.y.0. This
         | builds release candidates. We have a sanity check on Friday,
         | then our remote QA team runs through them over the weekend. Any
         | issues they find, we try to have squared away by Monday,
         | Tuesday at the latest.
         | 
         | Meanwhile other team members are still merging new things into
         | develop. It's useful to have that release branch because it
         | lets the rest of the team keep moving - we maybe only put out 1
         | or 2 developer's features each cycle, the rest are still
         | trickling in.
         | 
         | Once we release, we tag, merge into master, and start over
         | again. If any issues show up on production, we use the hotfix
         | branch, hotfix/x.y.z. That let's us resolve issues with risking
         | a ship of any of the changes that have come into develop that
         | haven't had a few days of stability behind it.
         | 
         | For our team scale, we have a lot of users (100k's DAU), and we
         | find this method is a nice balance between the pace of output
         | you might get from true CI but with the reliability of a more
         | traditional cycle.
         | 
         | Backend and web projects, however... Straight CI, into master,
         | and we roll out test > staging > production when we're happy.
        
           | debaserab2 wrote:
           | I basically follow the same protocol as you up to this point:
           | 
           | > Once we release, we tag, merge into master, and start over
           | again. If any issues show up on production, we use the hotfix
           | branch, hotfix/x.y.z. That let's us resolve issues with
           | risking a ship of any of the changes that have come into
           | develop that haven't had a few days of stability behind it.
           | 
           | In our case, there's no point in a hotfix branch because
           | master is always considered stable. You don't merge to master
           | unless you're ready for that code to hit production. Feature
           | gates are used for hiding live code when necessary for
           | marketing announcements or if the feature simply isn't ready
           | for actual customer usage yet (sometimes we leave the
           | endpoints live but turn off all the navigation to the
           | endpoint so we can send out the link as a "beta" test for
           | specific customers).
           | 
           | This does occasionally cause problems with feature branches
           | lagging behind, but it's on the developer to ensure that
           | their code merges into master smoothly (usually best done by
           | syncing your feature branch back up to master frequently)
        
       | arghskwidge wrote:
       | AFAICT Gitflow just has one more branch than it needs. If you got
       | rid of the master branch and supported production releases off
       | release branches it would be just as useful and significantly
       | less complicated. Can anyone explain to me what real value the
       | master branch adds in this model? And without using fluffy
       | meaningless words like, "source of truth," please.
        
         | Chilinot wrote:
         | I fully agree. Removing the master branch which is just fluff
         | that noone uses you essentially come to trunkbased development.
        
         | raziel2p wrote:
         | The main advantage I can think of is you can just configure
         | your nightly expensive CI jobs (running absolutely all e2e
         | tests) to run against a static branch.
         | 
         | Another might be that git clone gets the "correct" branch by
         | default. Might be important if your git repo gets cloned by
         | sales, support or whatever for external demo purposes.
         | 
         | Anyway I don't think it makes a huge difference in complexity -
         | it's rarely used for developers' workflows and doesn't even
         | need to be updated that often.
        
           | pdpi wrote:
           | How meaningful is it to run build/test against a branch that
           | is reflective neither of a release branch nor a feature
           | branch, though?
        
         | jordigh wrote:
         | I don't really understand the distinction between develop and
         | master either. You're supposed to branch off develop and merge
         | forward back into develop, then merge into a release branch,
         | then merge into master. So everything in develop is supposed to
         | end up in master.
         | 
         | So... why not branch off master and merge back into master?
        
           | ozim wrote:
           | Master is current production version. Develop is current
           | development version. You branch off develop to work on your
           | feature, then you merge it back to develop so you have
           | integration point with your co-workers (you fix conflicts
           | here) which can be deployed to test server or just run
           | through automated tests. When you have develop branch in
           | correct state (whatever that means for your team) then you
           | merge it into master creating new release on production.
           | 
           | This way in case of some unforeseen bugs you can fix master
           | which is production like and then merge that fix also into
           | develop so it is present in next release. If you would
           | develop on master you don't have obvious "production like"
           | place. You could do tags, but somehow it fits better with CI
           | setup and Jenkins.
           | 
           | In our team we have acceptance branch instead of "release
           | branch".
           | 
           | Feature branches are short lived, develop, acceptance, master
           | are long lived branches. You also don't mix stuff because
           | what you really want is one way direction of promoting
           | changes develop->acceptance->master.
        
             | [deleted]
        
           | kubanczyk wrote:
           | There is a small trade secret, that's hard to visualize. If
           | you merge two changes into master you can break it.
           | 
           | The fact that a change passed a CI and another change passed
           | a CI doesn't mean they can merge and the result is guaranteed
           | to pass CI. It will often break and if you think for a minute
           | you will come up with really rudimentary examples of this.
           | 
           | The really primitive solution is to call the merge-recipient
           | branch the "develop" and only merge to "master" when you are
           | sure what you are merging is good. You'll be ok if you do it
           | sequentially (no parallel merges to master).
           | 
           | A more complicated solution is to actually test (in CI) "what
           | happens when I merge this" but in hiding, without showing it
           | to others. Even more complicated is to do it in parallel.
           | Gitlab calls it Merge Trains (Premium only). Zuul-CI calls it
           | gate/gating and has a pretty good description here:
           | https://zuul-
           | ci.org/docs/zuul/discussion/gating.html#testing...
        
             | qznc wrote:
             | This is true. Another explanation could be a two stage
             | testing process. The CI test for develop might run quickly
             | in a few minutes, but the test suite for master might run
             | for a day or require manual testing.
        
       | nilsandrey wrote:
       | Strongly agreed with the new author note. I used the same ideas
       | with the teams I've been coaching: "Consider your context...." as
       | the need or not of support for multiple versions and "...Decide
       | for yourself.
        
       | kureikain wrote:
       | A problem with GitFlow is it's painful to follow PR model.
       | 
       | Especially on the Github repository where pushing to master is a
       | lock and can only done by PR and merge(or squash or whatever).
       | 
       | Let's take a look at a release:
       | 
       | 1. Branch of release/1.0 from develop 2. Fix some bug, then at
       | the time of deploymennt. Merge it back to master _and_ develop
       | 
       | But once we merge, github close the PR... If we attempt to create
       | another PR for other branch. The Github now see different history
       | between master/develop...
        
         | cfstras wrote:
         | There exist scripts and workflows to perform auto-merges from
         | all release branches back to master. This way, you only have to
         | care about branching off releases, and hotfixes will
         | automatically land on develop once released.
         | 
         | (Assuming master is your "next release", and develop is your
         | main development branch)
        
           | kureikain wrote:
           | Like I said, I cannot merge because we cannot push from our
           | computer to Github(It's locked).
           | 
           | The only way to get code into branch is by doing a PR, and
           | click merge button on Github UI. But a PR cannot be merged
           | twice.
           | 
           | And If I open two PRs two master/develop then I will see this
           | kind of error on Github: "This branch is 1 commit behind. 1
           | commit ahead of develop"
        
             | cfstras wrote:
             | the way to go here is probably creating an "administrator"
             | account which is used by those merging scripts, and allow
             | push access to protected branches for administrators.
        
       ___________________________________________________________________
       (page generated 2020-03-05 23:01 UTC)