[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)