Lots of people often code using feature branching on git to avoid the hassle of conflicts while doing pull and/or to avoid pushing incomplete features that would break the system for all the team.
I find these reasons to be baseless and some even harmful to the development cicle. Trying to develop in your little temporal bubble without being distracted by the rest of your team it's a bad idea, imagine the following:
A team of five people have to do a painting of a big landscape, so they split the canvas in five pieces and then each of them paints their part without even looking at what their partners are doing and in two weeks they put all the five pieces together to deliver the product. What do you expect will happen? of course the painting will be a mess with miss aligned items on it that will need to be redrawn at the last minute pulling an all nighter on the worst case. Sounds familiar?
How can we work on a single branch without breaking stuff and without continuous conflict?
First the conflict part: Communication is key, daily meetings are there for a reason and should be used to smooth cooperation between developers working at the same classes.
Now, the scariest part: How to commit half baked features without breaking stuff? or even more, how to commit a new feature that we aren't sure is working correctly? Well, one of the best things about everyone working at the same branch is that if something breaks it will be noticed quickly and fixed at an early stage and therefore less painful process.
For the part of committing without breaking the system for everyone there is a very good technique called "feature toggling". Basically what you do is put an if like this:
if (useNewLogic) {
awesomeNewFeatureEntryPoint();
} else {
legacyEntryPoint();
}
This allows to run the new code when you want and where you want without risking all the environments and such.
This way of working also benefits of the fact that because everyone is working at the same place if your new feature conflicts with some change of class contract you can fix it quickly, it means that you are doing continuous integration.
One way I have found in my personal experience that people that comes used to work with branches feels more comfortable to do the switch is to have two branches, for example: develop and master. With the only way to put things on master is via a pull request.
I would love to read your opinions of this matter on the comments.
Top comments (179)
I disagree with most of this article, but respect that it works for you.
Any project I've ever worked on where multiple people are commiting to the same generic "development" branch results in lots of merge conflicts unless people are super careful to always pull the latest changes and merge master often. It's also difficult for audit purposes in the future because many features will be added simultaneously on every PR merge.
If anyone decides to try this, I highly recommend that you keep a changelog and follow some sort of commit message guideline.
In my experience, proper use of Git Flow, CI/CD tools, PR status checks, and merge conflict resolution as needed should take care of most of the issues you have with feature branching.
Some useful Git tooling:
So my team practices continuous delivery / continuous deployment. The idea here is that we're always pushing to master and deploying to live, leaning on our tests to ensure integration. There are other ways, but it's all essentially 'trunk based development' and is definitely opposed to 'git workflows' á la Gitflow.
We're not large, and we're 'colocated' (management speak for 'sit together') so that might be a factor.
A caveat: I am definitely not an expert at any of this.
You don't need to be 'super' careful. You just need to
pull -r
from upstream on a very regular basis. I mean, every few minutes. The first point of integration of your code is your machine, the first tests of integration are on your machine. You hit a merge conflict sometimes - it inspires you to pull more often.There are no PRs. There are no merges. There are only commits, to master, on your machine, and rebased pulls.
Everything you push will go live on a continuous delivery pipeline. So you cannot be lazy - you must write automated tests to document the features you are implementing.
The key driver here is continuous delivery - no 'releases', no 'big bang deployments'. Just the regular (every 15 minutes usually) integration and deployment of code to live.
I do agree the original author is saying some odd stuff, like:
Just don't deploy broken code. But, conversely, if your code isn't breaking the tests of your other features - then nothing is broken. Feel free to deploy.
A corollary to this: break down your 'features' into small, valuable, deliverable parts. Stop swallowing the elephant whole; use a knife and fork.
Feature flags are a good idea - but only to separate deployment from delivery (i.e. deploy code but prevent its 'delivery' to the user in live). But they should be extremely short lived and probably live in the interface layer. They should not be quite unusual.
Take a look at these just to make sure I'm not mad...
and also
Why you should deploy on Friday afternoon
Chris James ・ May 28 '18 ・ 7 min read
Maybe I should write some of this stuff up in a post if there's interest?
Not all heros wear capes. Some have the power to merge code. Fully agree
I really cannot agree with this approach at all. It is dangerous to suggest this for new programmers looking for guidance. This defies the whole point of Git which is to decentralize development so that only working, tested code gets put on the main line. Adding logic switches creates complexity, untested pathways (even only 4 logic switches is 24 possible execution pathways), and requires cleanup work and refactoring once completed and agreed upon by the team.
If you want to work like this proposal suggests, just use SVN. However, reflect on the fact that there is no such thing as svnhub for a reason.
If you have a good CI system (it's 2018 we all should have one) nothing untested nor unclean code enters the repo.
I am not going to try to convince you against your thesis. However, I believe you have missed the point of Git (and other decentralized version control tools). Branches are not meant to be lived in for ever, in fact we enforce strict rebasing or develop merge commits into branches throughout their lifecycle. The CI is run on each branch, each mainline, and each bugfix line for every commit. I encourage you to check out my project to see how branching can be very successful: github.com/keepassxreboot/keepassxc
The develop line stays absolutely pristine such that we can post "nightly" snapshots without worry. Nothing is merged in until it passes the branch CI and a merge CI.
I'd say he does understand git, but simply chooses to use it differently. In my company we do not use feature branches, unless absolutely necessary, which would mean a big rewrite of a considerable part of the system, where you just can't roll out changes progressively. It happened like 3-4 times in my 3 years of working here.
The issue he brought up with feature branches, where people work in separation from each other, is pretty substantial (not unsolvable, but still). Imagine you need something from another feature branch, but it will not be merged until a couple of days, because there something else needs finishing on that branch. And also, that required thing is based on lots of other changes made on that specific branch, so you can't just cherrypick it. Now what, rebase on a partially finished feature branch? Manually copy paste the code? Now, what if you need things from more than one feature branch?
In my experience, it is best to simply compartmentalize changes in a way, where a PR to master branch contains a small subset of changes that does not break anything. That way the changes are incorporated by the rest of the team and they can provide you with an actual feedback and vice versa. I know that is not always possible, but I would advocate for this approach in most cases where it is applicable.
I cannot agree more with the notion that there are many 'correct' ways to use git.
In the scenario you're talking about, where Developer A needs some code from Developer B, but that code has dependencies on unfinished code that is not ready to be incorporated with master, I would argue that having that code on master instead does not improve the situation. If the unfinished code were on master, it would imply one of two things; Master is broken, or you're using feature flags. If you're using feature flags, you would have been able to cherry-pick the necessary code onto a separate branch and merge to master.
I would argue, however, that it's the development process that matters here, not the git workflow. If you're consistently finding that you need work from other features in order to complete your features, there are probably other things you should consider: Are your features broken down enough? It could be the case that the work needed by both features should have been done and released in a previous task, as a prerequisite for the two tasks that need it.
The team I'm working on uses feature branches, and also deploys to production multiple times a day. There are other teams who do not use feature branches, but still have many of the issues feature branches are suggested to create. At the end of the day, I think most of the problems brought up in this article and in this comment section are not caused by feature branches.
This is a great point, thank you.
Have your developers commit their unfinished branches to the repo (but not master), or use forks, then you have access to their code. Easy. Seriously, I push my branch to remote repo often because there's almost nothing in life worse than losing code (except maybe root canal). So if I screw up my personal work computer, delete something or the hard disk goes bad, I have my latest work safe on a remote repo.
I'm not sure what kind of CI setup you're using (maybe some kind of server hook?), but every CI system I've used (Travis, GitLab, Jenkins) would require code to enter the repo in order for the CI process to run. The CI process isn't going to prevent bad code from entering master; you just end up with a red build on master. Unless of course you use feature branches and use your CI build outcome as a quality gate. But you're advocating the opposite.
Sure. How does a feature toggle work when a feature requires a change to the build process?
Do you feature toggle the build instructions too?
Build steps:
If all green then build the artifacts and ship it.
What feature can require to change that?
What if something is red and I need to ship a bugfix?
If you use trunk based development and have a decent continuous deployment process, you don't ship a bugfix. You rollback production to the previous release version, revert changes in git, then add a regression test that fails due to the bug, fix the bug and then commit.
My bug is not in the latest release so "You rollback production to the previous release version, revert changes in git" won't help.
"Fix the bug and then commit" is exactly what I was referring to as ship a bugfix.
The problem here is not how to ship a bugfix or how to revert/rollback changes. The problem here is what if I need to send code to production if the trunk is unstable.
In my environment a "bug" is not always like that. I can be something that has been there for awhile so you cannot roll back. Also the bug may be due to something missing that should be there. The bug may be related to an essential feature that you cannot just roll back entirely. You can't roll that back. Plus you also have environmental issues like a new version of a browser ships and you have to deal with something that a rollback cannot fix.
HOWEVER, if you discover a bug close to when that code was released, then rollback and breathe a sigh of relief, and fix it un-rushed.
I agree that using branches can be used to develop your features in a bubble. But I think that is a great and awesome feature of git. Perhaps the most important one. You can focus on your stuff in your little bubble, and after you think you're done you just rebase to the develop branch to get all the latest stuff in, and then fix whatever broke.
After your stuff works again, you do the rebase again and repeat this until there is nothing to fix, and then you make the pull request and let others review and then approve it. I can not see how this is a bad thing. Also we at our team are not making pull requests from half-baked stuff anyway. And we rebase often, multiple times a day, which keeps the codebase fresh and prevents the large hassle of fixing the code after it's "done". There are no excuses to not do rebasing multiple times a day, and we have integrated it seamlessly in our workflow.
Do small commits, rebase after each one. That's a recipe to success instead of having to fear large conflict resolving when you're done with the feature.
Just my two cents.
Then you realize is 4am and all of you are still on the office because two guys on their bubble made architectural decisions that impacted each other because they forgot to rebase frequently and now all of you need to code a third set of classes to handle the communication between those two subsystems.
No thanks I don't want to return to those nightmares.
Sounds a lot like there is a problem in communication and planning. This is not because of git or branching.
Nothing is because git or branching, those are just tools what I like about not branching is that it doesn't requiere for the developer to be systematic and remember to do this and that.
If the developer isn't going to be systematic, how well do you think the product is going to work?
Well enough if you have a well configured CI server and QA processes.
I think this is more of a band aid approach which will eventually lead to further problems. If the issue is communication then you should fix that instead. Committing directly to development doesn't mean you resolve the issue of two individuals who decided to implement their own architecture. It just means if you weren't communicating then you get to see it sooner when you pull their recent commits but the issue still exists. It's just now it's been committed to the main dev branch.
and you fix it when is still a minor issue instead of a fully developed feature with, in the worst case, several days of work on it.
Communication problem are unavoidable or so says my experience.
CI is not a fix for bad planning and bad code. Fix the communication and planning and you end up with surprisingly good results. CI exists to help with quality, but the quality must start from the planning. CI does not help with maintainability and performance. Maintainability and performance directly affects to upkeep costs of the project.
I think you need to read a book called The Clean Coder. And The Phoenix Project while you're at it.
"and you fix it when is still a minor issue instead of a fully developed feature with, in the worst case, several days of work on it."
This again is a communication issue. Poor architectural design or not following implementation guidelines will not be resolved by checking in directly to a dev branch vs having a feature branch. It actually results in forced roll backs because things are being directly checked in to the same branch as everyone else. Just because they checked in code directly into the dev branch does not mean they didn't implement something incorrectly and didn't spend several days doing it.
Proper use of PRs for code reviews and communicating implementation with the team will help alleviate this issue.
There are different projects with different people and different needs. For my research project, where most of developers are non-professionals and do not follow all the rules (and cannot be forced), we use only single branch. It may sound crazy and really counter-intuitive, but it works best. People commit small and often, mistakes and bad code get quickly noticed. Everything is exposed to others and not hiding in their own branches. We don’t even have resources to do much code reviews. But main branch is heavily tested and we use CI. Now, all the features are in the maim branch and work together. Earlier (with cvs, svn and git) we ended up having dozens of branches living on their own since many people never cared pushing them to master. Or if they did, they ended up into integration hell - while sorting the merge problems somebody else pushed his 3 months work to master. Yes, we have a communication problem since the project is very loose. Now, we have always a working version on single remote branch (except occasional hickups between pushes and finished tests). Branching works well only when it is tightly coordinated. Of course, people still can have local branches.
Our “project” is quite special, what I want to say that not all projects are the same.
I think just because some are non-professionals (I assume they want to someday be one) it doesn't constitute bad practices. I think it's important to teach good practices so that they can use good practices moving forward. I also disagree that branching only works when things are tightly coordinated. I think when everyone is on the same branch coordination becomes even more important because you are on the same branch. Again working on the same branch will not prevent someone from pushing in 3 months worth of work.
You are right, it does not prevent. But most people do follow the commit small and often principle. The important thing is that code gets as early visibility as possible and it is not hiding anywhere. In a loose and distributed team, the early pushes serve as an important way of communication - hey, my name is N.N. and I am working on this feature. Often, others step in and propose a better way to do it. In separate feature branch, it often happened that a guy worked months on conflicting/duplicate or badly implemented feature. Then senior developers noticed the problem too late. Then we were left with 2 bad options, accept bad merge to main or loose months of work. In both case, we have at least one angry and frustrated developer... Although we try to force people (esp. the newbies) to communicate their plans in Jira before they do single line of code. Another major problem was that earlier certain branches started to live their own lives, causing serious fragmentation of the code base.
I understand the importance of code visibility and this can easily be done with feature branches via a pull request that does not get completed until code is reviewed and accepted. Direct commits and push to development does not fix issues of poorly implemented code. A developer can easily lose months of work because they committed to their local development branch that tracks origin and then push all their work once. The issue here is that you now are faced with an issue where that code is now in development and you have no chance to deny or approve it. This results in higher need to roll back commits on your development branch as opposed to only accepting code that meets requirements.
You have to prevent people from committing to master willy-nilly. Either make master a protected branch and require the tech lead to approve any merges, or have an automated regression test that runs before merging to master. At least make sure it compiles, or runs even a small "smoke test" (for non-compiled languages)
If a problem comes up, the person who caused the problem has to fix it, and it hasn't polluted the working master. The simplicity of that is probably too much for some people.
Another way to put this is avoiding feature branches enables a team to achieve better continuous integration. Its related to continuous delivery and continuous deployment but those are downstream benefits to achieving better continuous integration.
A team can use feature branches and still achieve a high level of continuous integration, but it requires more discipline.
Reading this discussion, I think I have concluded that there are a lot of pain points for a team to encounter when switching from feature branches to trunk based development. However, I think I would argue that those pain points already exist and just aren't as apparent when using feature branches.
I think something to consider for all the nay-sayers... The author sounds like he has working experience on teams making branches and on teams without branches. He also claims that having a workflow that doesn't involve branching has aided in communication and healthy coding practices. Most of the people arguing against what he said seem to be in the realm of theory. But he is actually letting you know what his practical work experience has been. There is a difference in theory and actual experience. The author isn't theoretically saying he thinks this works better, he is saying he has literally experienced it working better. Git and branching are tools that you and your team can use as you see fit. If you don't want to use the same tools the way he is suggesting that is fine, but why are people trying so hard to convince him he is wrong? He already knows whether or not his teams workflow improved by making the changes he told you about.
Then you have a crappy team, somebody failed to communicate how to work on the team or something else; definitively flesh based problem rather than software tooling problem
Same problem as you described in the original post and same solution: communication.
Do you realise, that you have much bigger problems with your development process and colleagues, than how you use your source control system? Seems like a big mess and here is why:
You need features from other incomplete branches, i.e. you are not planning ahead correctly and your branch lifespan is too high
Your colleagues can't properly use git and branches just like you (why am I not surprised?)
You need better tools to merge code maybe (can I suggest Araxis Merge?)
Everyone works on their own and nobody knows what the other is doing, then you are "surprised" of the outcome and you have to stitch it all together.
Don't be offended by my words - I intentionally wrote it this way, so you can pause and think a bit.
Exactly my thinking. They have serious issues in how they work, I also bet it's not a team that one enjoys working with, and they just blame it on "the system".
I'm pretty sure their task breakdown is also wrong and they start working on huge epics in one branch without properly splitting the work. Probably their tech isn't allowing it.
Chalking things up to poor communication is like saying that the key to standardizing deployments is better documentation. Its true that a wiki can work, but why leave it up to human error when there is a better solution which is automation? Automation is essentially working documentation so you were right if you said the answer is documentation, however, I would give a better grade to the person that answered 'working documentation' over 'documentation'.
The problem we are talking about here is having people and teams come out of sync that can result in integration issues later down the road. Better communication is the right answer. To me, trunk based development essentially means 'working communication'.
I recently left a large codebase that didn't branch. I worked in this code base for 3 years.
As a result, we were forced to cherry pick change sets ready to deploy into a stage branch.
Once stage was certified, we had to again cherry pick change sets into a release branch.
The amount of feature flags required to support this would have been unmaintainable.
The amount of bugs that resulted from this were incredible.
The only way to describe it was a nightmare.
I don't see any possible way a large team can work in this environment.
I would never recommend "no branches" to a team over 3 people.
Because you guys were branching you had all those problems, from your comment I can see at least 3 branches being used.
That was not the cause of the problems. It was the symptom.
The cause was a failure to create a proper branching strategy from the beginning.
No it isn't. Your problem is you are scared to release your own software and instead you are cherry picking changes in your trunk.
Being scared lol. I can tell if you are you being serious or a troll. Has to do with a multi tenant platform that has SLA with it's clients that gives a 30 day review period to sign off on any changes before prod it's updated.
There are legit compliance reasons for staging deployments.
First, the analogy of splitting the canvas into 5 doesn't work. Even though you're working on a single feature, you can see the whole canvas and (one would assume) you're communicating to make sure that the changes are harmonious.
Second, feature toggles are a bad idea in my opinion. They basically translate to increasing the cyclomatic complexity because someone can't decide whether a feature should be on or off. The real problem isn't branching, it's indecision and poor planning. I could very easily see four or five half baked features becoming a testing and maintenance nightmare. If you do this for any length of time, your "bitfield" of features will be a lot more than 4 or 5. Good luck changing things when you realize a half baked feature needs a design change in order to complete and you have a few other half baked features to deal with.
Branches are good for a reason. They follow the UNIX philosophy of "Do one thing and do it well". Nothing will replace good planning and prioritisation.
While feature toggles might seem good in the short term, you're essentially building up more technical debt than you need to and are accelerating paralysis due to it in the long term.
Finally, I'd say if branching on Git is actually wrong, then why is it the cornerstone of so many CI/CD workflows? These workflows have been designed by extremely smart and experienced people and have been proven to work. So either you're missing something or the rest of the world has. Which do you think is more likely?
That is the idea of each project, then reality comes and some people don't even listen on the daily standup much less take a look at slack or whatever they just want to be left alone and code.
If the feature is marked as delivered then it should be on unless it creates a critical bug on production.
You will have those you want it or not therefore I prefer a system more resistant to it.
Don't bite more than you can chew. Why start 5 new features if your team can only handle 2 per sprint?
It sounds like the problem you're experiencing is lack of communication and agreement. Code isn't going to fix a human problem.
I suggest you tackle the problem at the layer it manifests instead of trying to reinvent a square wheel at a lower layer.
After years of working on several companies and projects the only thing I saw in common were two:
If you have some suggestions on the communication part please tell.
Based on personal experience, I would say, don't give in. Instead push for change, hard. Sometimes you will hit a brick wall and will have to move on. But then you find a team (and a manager) that's a joy to work with and work becomes a pleasure.
The last company I worked at had every dev forking the repos they were working on, and then making PRs to the company repos. For me (being a messy brancher) that worked pretty good, nobody could see my mess, I obviously only committed clean working code, and the company branches were clean and few.
Interesting approach.
wait, you are posting an opinion about git branching and you never heard of forking? this, i think, tells us everything we need to know.
Of course I know what forking is but I never seen a company working that way.
I like that approach. Sounds like it would work well with really large codebases
We work like that in my company, this is a very good way for branching without messing with the main repositories branches 👍 Pull request in a lovely team, this makes all my days at work 😍
This article confuses long lived branches with topic branches.
1) long lived branches are the worst and I'd rather not have branches if long lived branches were unavoidable.
2) not all branches are long lived, and short, feature specific branches are a useful tool to organize developement.
Your feature toggling is the worst suggestion I've seen in a long time. Although it's common to see this, it leads to code rot and maintaining code that's not used. If you're good at organized feature branches, you can immediately toss the old function and get it back in a merge free revert with one command. Forking the code for different versions is every devs worst nightmare.
If you were talking about long lived branches (stuff that lives longer than a sprint) then I would totally agree with most of what you said.
To put this back in your painting analogy, topic branches are more like brush strokes and each time you make one, you get a chance to step back, see if that made it better and find where in the painting it makes sense to work on next.
Having a clean history, and being able to review changes on a topic by topic basis are the hallmarks of git and it's power. When you can just revert a merge commit and cleanly delete a feature the night before a deadline, you'll understand the power
Wow, I'm surprised by the negativity to this post from the majority of the developers here. The idea is spot on, but the article title and tone could be better - as in all things there is rarely a right or wrong answer to a problem.
I'm gonna argue the case for using one one branch - trunk/master. It may not work for your organisation, but for my organisation it's an essential way of shipping features to customers quickly.
We have 40+ engineers and we all commit directly to trunk - no branches, no pull requests, no QA department. Every push to git is deployed to production, provided that the push passes the pre-push test and quality checks, CI automated tests, etc. We pair-program on pretty much everything, the extra set of eyes is the equivalent of a pull request for us.
When bugs are introduced, it's trivial to rollback production to an earlier version and identify the commits that have likely introduced the problem. It's much harder to identify where a bug was introduced when you have multiple changes from multiple feature branches. Adrian is right failing fast is good! Quick feedback loop is incredibly useful. (That's why we all practise TDD, yeah?) When a problem does happen, engineers quickly pick up on the issue. ("Oh yeah, that was my recent commit on XYZ, I'll rollback production now and then revert those changes"). They are in the zone at that point. Compare that with a release that introduces a bug and engineers are already on a different task or feature. They have to context switch back to the earlier work, which makes problem identification harder. All engineers using the same code base and pushing to production daily helps with this rapid feedback loop.
Feature flags are not used simply as an on/off state to control "half-baked features" not being released. If you want to perform experimentation on your features or canary release features then feature flags are a must. Services like LaunchDarkly or SplitIO can provide matching rules for feature flags that allow you to target cohorts of users and give those users a different UI experience or feature. For example, we can easily create a new sign-in page and target 10% of all users to use that sign-in page while the other 90% get the existing sign-in. If all goes well and we don't get any major problems we can continue to rollout that new page to more users. Increasing or decreasing the percentage rollout is a configuration change and is instantly reflected on production. Experiments are also easy to implement with these feature flags. (For example, what's the affect on user registrations if we change the text? Make the register button bigger? Add a coloured background to the register button?). The results of these experiments allow us to continually improve the customer experience. Experiments and canary releases can also be turned off instantly (no deployment needed!).
If you don't want/need to deploy to production daily, then feature branches will work just fine. But, if you want to move towards continuous deployment, rapid feedback on experiments, canary releases then trunk based development and feature flags is a good approach. It's scary at first, but it's worth it. Not one of our engineers will go back to the bad old days of feature branches and merge conflict hell.
Ask yourself which is more likely:
Above all, the purpose of branching is to isolate the impact of said changes. Feature toggle works well in most cases, but not all. It does not handle dependencies well, for one. Also, how do you run your integration and functional tests? With all changes in develop, these will be failing all the time.
The worst part of "gitflow w/o feature branches", I believe this is what we are talking about here, is that a defect introduced by any of the teams working on develop will impact all other teams as well.
The CI server does it for me.
That is the idea, you want to fail fast to fix it faster.
reddit.com/r/ProgrammerDadJokes/co...
Some comments may only be visible to logged-in visitors. Sign in to view all comments.