loading...

why branching on git is wrong

anortef profile image Adrián Norte ・2 min read

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.

Posted on by:

anortef profile

Adrián Norte

@anortef

I have been developing software and doing sysadmin work as a profesional since 2008 and I'm also a proud cat father.

Discussion

markdown guide
 

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.

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.

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.

It's also difficult for audit purposes in the future because many features will be added simultaneously on every PR merge.

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:

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?

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

Maybe I should write some of this stuff up in a post if there's interest?

 

Good ol gitflow with pull requests. "Gateflow," if you will. Personally I don't mind it at all and like PRs, however I've worked at orgs that got just as far with manual CRs on a trunk model. It usually boils down to how much you trust your devs, or the dual, are they skilled and reliable enough to not need the merge control hand holding.

 

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.

 

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 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'd say he does understand git, but simply chooses to use it differently.

I cannot agree more with the notion that there are many 'correct' ways to use git.

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 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.

 

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:

  • execute unit tests.
  • execute sonarqube analysis and coverage.
  • deploy it on a testing environment.
  • execute integration tests.
  • execute system tests.

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.

 

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.

 

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.

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.

 

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:

  1. You need features from other incomplete branches, i.e. you are not planning ahead correctly and your branch lifespan is too high

  2. Your colleagues can't properly use git and branches just like you (why am I not surprised?)

  3. You need better tools to merge code maybe (can I suggest Araxis Merge?)

  4. 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?

 

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.

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.

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.

If the feature is marked as delivered then it should be on unless it creates a critical bug on production.

The real problem isn't branching, it's indecision and poor planning.

You will have those you want it or not therefore I prefer a system more resistant to it.

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.

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:

  • lack of communication.
  • the managers always wanted more.

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.

 
 

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.

 

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 😍

 

I like that approach. Sounds like it would work well with really large codebases

 

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

 

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.

 

how do you run your integration and functional tests? With all changes in develop, these will be failing all the time.

The CI server does it for me.

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.

That is the idea, you want to fail fast to fix it faster.

 
 

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:

  1. You are using the wrong tool for your workflow
  2. Everyone else is using the wrong workflow for the tool
 

What I don't get about this argument is, with distributed version control, in a sense everyone "paints their part without even looking at what their partners are doing" even if you don't branch. Unless everyone regularly pulls from the repo, they're only going to see what's in their checked-out copy.

If you want to mandate that they regularly pull in order to stay up to date with others' changes, you can just mandate that they regularly merge master (or develop or what have you) into their topic branches.

I don't see how organizing or not organizing your own development into topic branches affects how integration with the rest of the codebase is handled. And as someone else pointed out, if every developer has their own fork of the code (the GitHub model), then that adds a further wrinkle that even this crazy "no branches" position doesn't solve.

I feel like this is trying to solve the wrong problem, by thinking that branching is the problem.

 

Without branching you can't have pull requests. Without pull requests code reviews are very difficult. I work on shared repos with as many as 10 other devs working on feature PRs at a time and this simple model just won't work for us.

If you think about it branches are just "groups" of commits. Being able to break big features down into small commits and group them is actually something that helps avoid conflicts and increase communication in my experience.

The only time not branching ever worked for me was back when I first started using GIT and was basically just a single developer that used source control as a giant undo history.

 

In my personal experience PRs are almost useless unless all your team knows how to do them well. In my opinion PRs cannot beat a well configured Sonar + CI Server.

 

Then you have no idea what you're talking about. You can configure PRs such that if the code is not building, or passing tests, it will never be possible to merge that code to the main branch. With your approach, this is not possible and who knows if you even pay attention to failing tests at the moment. Because when you're not FORCED to solve these issues, sooner or later somebody will say to leave it to later, because now you're busy with other stuff.

Also, you still didn't answer how you conduct code reviews. I'm guessing you don't. But even if you do, the result is that code pushed to main development branch is messy.

In some other comment you mentioned that developers changed architecture in their feature branches. Well, with code reviews, you'd see that and comment on that and tell the developers to not change the architecture, or resolve the situation before it gets to main development branch.

I'm thinking maybe you just never worked in a technically mature team and you never conducted proper code reviews and that's why you have these opinions.

 

PRs cannot beat a well configured Sonar + CI Server

There is no race between those. Those are supposed to work together.

 

You have an amazing Sonar + CI Server if it can give warnings for inappropriate architectural approaches, business requirement issues, or rolling your own libraries when those already exist in the codebase or in existing dependencies.

 

"PRs are useless".
I'm seriously more and more horrified I would accidentally one day work for that team. I'm sure I'll see a nightmare tonight. Dude you need a good mentor who can show you how it's done. No offense, try to work with people having worked abroad and have a wide experience in leading teams. You have many misconceptions and dogmas.

 

You're treating the symptoms not the cause, and misusing tools in the process.

Your team shouldn't be going off on their own for 2 weeks at a time, they should constantly be pushing small PRs. They should be constantly reviewing these PRs so they know what's going into the codebase, and your codebase should be decoupled enough that conflicts are rare.

 

What's the difference between constantly pushing small PRs and just committing to master?

 

If someone writes a mess of a PR, it will get hung up in the code review process until it is clean. The only people it will affect are the writer of the PR and the reviewers.

If someone writes a mess of a commit and pushes it directly to master, it affects everyone who wants to push.

What's to stop the PR process pushing something that is "a mess" ? We're not all knowing and make mistakes.

The beauty of software is that it can be changed, so if someone pushes up a "mess" then it can be fixed.

In practice, if you trust your team... then people wont be pushing "messes". Sub-optimal? Sure, but its not a big deal.

The problem with this kind of ceremony is its trying to optimise for perfection, which no one is capable of. What you should be optimising for is fast feedback loops so you can quickly iterate to something that resembles useful software.

 

I strongly believe there is no one size fits all solution to anything. And for small teams 3ish and under this may work.

I also strongly believe in the "do what works for your team" motto.

If your article had some conditions, for example: very small teams, I could have agreed with you.

But a blanket statement saying git branching is wrong is not only false but dangrous and harmful.

Before branching, this is how software was done. And there were problems with it, which is why the concept of branching was created. To solve the problems with source control that didn't support branching.

For those of us that have been through the advent and evolution of source control systems, we understand why branches exist because we have experienced the pains of not having them.

 

Communication is key. But we also have another keys:

  • merge your master or parent dev branch into your feature branch often
  • avoid long lived branches

I agree with some suggestions you made, like feature flags. They help a lot to keep the branches short-lived.

 

All those premises are the same everywhere I worked that used branches, the result? Years old, thousands of commits behind and totally forgotten branches.

The problem with branching is that it actively requires the developers to be clean.

 

Forgotten branches are forgotten features or projects - they may happen with or without branches. All proposed solutions also require the developers to be clean at something.

I think lack of planning and communication are the main problems in these situations, or at least that was the case on my experiences.

 

writing new features and integrating them into preexisting code are/should be separate tasks. keeping them separate cuts down both on feature creep/"oh i'll just do this too while i'm here" and on tech debt caused by timidity in the face of old code.
relatedly, isolating features makes squashing/rebasing easier (especially now that github has those options), which makes pulling problematic code out easier.

 

Agree working in a bubble is bad.
Agree merging to master early and often is good.

Completely disagree with the premise that using feature branches causes the type of problems you describe.

There's definitely something else going on here.

Your feature branch should be short-lived.

You should be merging or rebasing Master into your feature branch one or many times a day so you have the latest commits from everyone else

 

I've got to agree with the rest of the sentiments left in this comment section. This is terrible advice and should not be followed. I've worked like this in the past and it's hell compared to gitflow or even a simple feature branch model.

 

A couple of years ago I'd have entirely disagreed with you, but after switching to trunk-based development when I joined my current job (i.e. that was what the company was already doing so it was something I had to do too) I'm right with you.

I think it's easy to think this will be a nightmare, but in practice I can count on one hand the number of merge conflicts I've had in the last 18 months, and they were all very easily fixed. This was the total opposite experience that I've had in the multiple places I've worked that used feature branches.

Edit: okay I do actually disagree with the clickbaity title, branches aren't "wrong". But yeah, I wouldn't be keen to switch back to them.

 

Conflict resolution is easy if you use the right tool. Do you use web storm or some other ide with à visual conflict résolution tool ?
Conflicts don't happen when you have a good architecture and everyone works in their own component. It also doesn't happen when you communicate and if you rebase often.

 

It's even easier when you don't have them in the first place. :-)

 
 
 

Respectfully disagree. This defies the whole point of Git. But if it’s working for you and your team, stick with it! These days I need to get things done fast and with as few bugs as possible. Use whatever technique saves you time.

 

So you disagree with the foundation of what git is all about. Branching is cheap, it is meant to used...a lot. Why not just go back to subversion and forget about using git?

 

Don’t agree with this at all. Suggesting that branching be replaced with further time consuming meetings and features toggles just seems ridiculous.

Part of your role as a developer should be a good understanding of source control and having processes in place to support the use of branching (planning, reviews, correctly identified tasks) is a lot more conducive to having a concise code base than filling it full of broken code and feature toggles.

 

Suitably controversial subject, especially for post #1, bravo :)

I note that nobody has yet mentioned structural issues, my first reaction to a situation where close co-ordination is required among a significant number of people (say 4-5+), is to question the coupling of the things being worked on - ask if there are better ways to structure the code so more people / teams can work unhindered (yes, apply Conway's Law!), look for more stable interfaces, domain boundaries, to partition work around.

If short term fixes are needed, perhaps ask if there are known working practices which would help like Mob Coding, or appointing a design authority role to make decisions that affect >1 person (this can be a rotating role, as long as there is someone the team can communicate with immediately for such decisions and they are shared).

 

I really disagree. Feature branching is an invaluable aspect of development workflow. I agree that code isn't written in a vacuum and individual developers must be aware of everything else going on simultaneously to avoid disjointed software and the bloat that comes with development each developer trying to be independent.

However, feature branching is not the source of these problems. Poor communication is.

My teams are always checking out each other's feature branches to understand changes being made. WIP pull requests are made as soon as a feature's scaffolding is clear enough to be understood by another developer. Comments are made right away suggesting improvements, warning of pitfalls or inconsistencies, or criticizing the entire approach. As commits roll in, particularly affected parties subscribe to notifications so they can see what's changing and discuss.

When developing, I spend at least 20% of my time in other people's branches, piecing together the way everything will work. When I notice divergence between the branches, I start a lengthy thread on Slack and we figure out how to tighten up our architecture.

What about when developing highly-interdependent features? Keep in mind that they're feature branches, not developer branches, and don't exclude cooperative development by multiple developers on a single branch. If the two features are small enough, we develop them on the same branch. If they're more complex, we will often create a branch that acts like a mini-development branch to create feature branches from and make PRs to. When the interdependent features are ready, we make a PR of this mini-dev branch back to development proper.

Trunk-based development (and adding in dev-environment logic) really misses out on the power of Git. The big advantage of version control is that untested code can be rapidly checked out and used without interfering with reliable code. It ultimately increases effort needed to commit and reduces frequency of commits, since developers need to be very careful not to commit code that doesn't work. Moreover, developers must rely on each other to keep the trunk in working condition. One mistake halts all development. No one can test their own features against known working code with the entire codebase in a state of flux. The larger the project, the greater the risk. Soon enough those daily meetings become week-long workshops that resemble change-board reviews. Eventually quality sacrifices are made just to get it working again due to the building pressure of all the developers waiting on the one problem to be fixed.

Git flow is scalable from an individual to a large organization, and allows concurrent, prioritized development with minimal risk of breaking the trunk. When implemented properly with CI/CD and proper merging permissions, there isn't a quality sacrifice. When WIP PRs are made early and a culture of checking each other's work is promoted, the code remains unified and everyone's concerns are heard.

I respect that trunk-based development has worked for you, and I know it's not always unsuccessful for small projects, but I've seen many trunk-based teams slow to a crawl waiting on individuals and become unable to easily produce working builds on demand because their version control was in their way.

 

Thanks for writing pretty much the comment I would have written.

 

Any agile methodologies will tell you to keep the features small and talk to your teammates regularly. Also, any good backlog grooming should contains evaluation of inter-dependance between features so special care is taken in those scenarios.

So I definitely agree with you that long lived branches are a nasty thing. However, I don't see were this has anything to do with git branching, gitflow or feature switches. Also feature branches allow to validate the team's "definition of done" in code review before integrating a features, so the team never have to put any feature in production that would lack test coverage, documentation or whatever the team deems important.

I suggest you to take a look at the INVEST mnemonic trick, to evaluate your backlog stories.
agileforall.com/new-to-agile-inves...

See ya!

 

This is not a great approach at all. Every time code is touched it should be it's own branch. This is exactly why Git mimics the structure of a tree.

Having a dev team work on the same branch can cause delays. If one developer breaks a branch it can halt development for everyone else. Unless of course, all members are at the same level of efficiency.

Having work on speperate branches allows for better code review and keeps a nice history of commits. If a developer leaves in the middle of work, another developer can pick up where they left of. They can also refer to a ticket with the same naming convention.

If the dev team has unit tests and CICD in place, they can catch the errors there.

I'm typing on my phone after a few beers. Not the best idea to comment in this state of mind.

I guess tagging could be an option as well, instead of branches.

 

I assume when you say "in two weeks try to piece everything together" that you are working in two week sprints in an agile process. The issue in my opinion is that the pieces you are working on are too big and needs to be broken down further. If the single thing you are working on takes up the entire two weeks of your sprint then it's too big. In my experience a good rule of thumb is that items you work on should be less than the sprint they exist in. Also a highly functioning team should know how things are being implemented through conversations and proper design specs resulting in less surprises.

 

I see where you are coming from, but I largely disagree.

Development, especially for big teams, should be loosely coupled. This doesn't mean that the team shouldn't meet and have a unified clear vision, on the contrary, this will allow things to scale properly and gives you options to add or remove features with minimal effect on the actual main branch.

Your painting analogy is a moot point imo, since painting is mostly done by one painter not 4 or 5 or way more, like in software.

A better analogy would be a car assembly line. Engine, suspensions and body parts are manufactured on their own assembly line and then they are put together when they are ready, wouldn't you agree?

 

I think this approach would change your day job from developer, to merge conflict solver...

I do agree that branches can start growing in separate ways which makes it hard to merge them, but if you keep your stories small, and not let your feature branches exist for weeks, but merge them within a day, or tops three days if there is no one available to check the pull request... Then I think the feature branches are a much better solution then the one suggested.

 

Well said. Small branches, quickly resolved is the way to go.