
Show HN: Why you should not use feature branches - jpdel
https://fire.ci/blog/why-you-should-not-use-feature-branches/
======
jph
A "feature branch" means something much different to my teams. A feature
branch for us is a short-life topic branch, and typically for one use case,
kanban card, etc.

We use short-life topic branches for each feature, each bug fix, each
infrastructure-as-code change, each documentation update, etc.

We prefer short-life topic branches vs. committing to the `master` branch (or
equivalent `develop` branch) because of multiple reasons:

1\. A topic branch gives good code isolation for distributed development: I
can share a topic branch with you, directly, without needing to merge to
master.

2\. A topic branch makes it really easy to do many kinds of popular git
workflows; this includes many popular CI servers, git automation scripts, git
aliases, etc.

3\. A topic branch is great for integrating early and often into code reviews,
and also with master. For example, we use a feature branch that uses feature
toggles, and we can do CI/CD to propose changes to master as often as we want,
and we can rebase the topic branch as often as we want. We can choose whether
a repo will prefer merge, or rebase, or rebase with preserve, and between
elided linear history or real graph history.

4\. We favor automatic integration, meaning when we push a topic branch, and
the reviews are all good, and the tests are all green, then the CI/CD does an
automatic integration process, including an automatic deploy. When the topic
is integrated, then the topic branch is deletable.

5\. Finally, I've tried the "TBD just merge to master" approach with multiple
teams, and inevitably it turns out to be significantly harder and more complex
to coordinate, especially at speed, scale, and with more stakeholders.

If you're interested in git, you can see some of the git alias topic branch
commands that we use:

[https://github.com/GitAlias/gitalias/blob/master/gitalias.tx...](https://github.com/GitAlias/gitalias/blob/master/gitalias.txt)

~~~
vidanay
How do you name your topic branches? We previously used a bug tracking system
in parallel with this same process, so we used ticket numbers as the prefix
for branch names. On our current project, we are using Trello as the driving
tool which obviously doesn't have the simple numbers so we end up with odd
inscrutable branch names and I haven't yet found a good way to normalize them.

~~~
jph
Each team is free to choose their own way. Personally I like topic branch
names that are read like a present tense imperative commit messages e.g.
add_feature_for_user_to_like_a_post, fix_relation_between_a user_and_a_post,
optimize_search_speed_for_a_user_to_see_posts. The names are long and
meaningful. Autocompletion makes these work well.

Our git commit message conventions are:

[https://github.com/joelparkerhenderson/git_commit_message](https://github.com/joelparkerhenderson/git_commit_message)

To store info about metadata, such as task board number, we edit the branch
description, and enable the description to go into the merge message.

A good short intro to branch descriptions:

[https://ericjmritz.wordpress.com/2015/11/13/using-branch-
des...](https://ericjmritz.wordpress.com/2015/11/13/using-branch-descriptions-
in-git/)

------
seren
We are using features branch that we are rebasing on master.

This allow to have code reviews before something is actually in master
(something you might or might not want depending on your worflow or criticity
of the sw you are working on)

Rebasing (and squashing) allow to keep a linear and clean history.

Rebasing and squashing also have downsides, you lose the finer day to day
commits, in exchange of ideal history, but at least it should be mentioned in
a 2019 post about having too much feature branches in git...

------
maushu
Someone forgot about continuously merging master to feature branch to keep the
merge simple.

~~~
rejschaap
If everyone is working in a feature branch and only bug fixes are done in
master, then most of the merges will be simple. However, when a feature is
done and merged to master, all the feature branches need to merge the work and
that merge will be disproportionately difficult.

kennethh posted a link that explains this well:
[https://martinfowler.com/bliki/FeatureBranch.html](https://martinfowler.com/bliki/FeatureBranch.html)

~~~
rurban
Only if you don't know rerere, and don't use it immediately after updating
master. I carry tons of feature branches with me, which are automatically
rebased. Only once or twice a year I need to fixup things a bit, and those
things are the things I immediately worked on, so I know for sure how to merge
it. Everything is scripted.

If you let them stall it becomes a mess, sure. If do it properly it's trivial.

------
golergka
Your git strategy should depends on your business release cycle and
priorities. In this case, it's a trade-off between dev branch stability and
development speed.

With trunk-based development, everyone sees everyone else's work in progress
and it's easier to integrate different features together. With feature
branches, however, dev is more stable and there's more responsibility on
merging to branch back to dev.

Are you deploying to public a few times a day like a web service, or are you
working towards an early release, like a AAA game? Does your team sit together
in one room, collaborating with one another, other do they take completely
independent task and do them remotely, working from all across the globe, with
the only point of interaction being a pull request once or twice a week?

It's impossible to say what's better or what's worse without these priors.

------
rglullis

      - "Show HN" when there is nothing really to show
      - Submitted by the author of the post
      - Author of the post is founder of company
      - Provocative, click-baity Headline
    

We are better than that, HN.

~~~
gus_massa
Submitting your own stuff is OK here. You can add some comment explaining that
you are willing to answer questions, but it is optional. Anyway, most people
here will assume that the owner will read the comments sooner or later.
(Reposting and reposting and reposting your stuff is not OK.)

Anyway, this is an article that is on-topic, but it is not a good ShowHN. From
[https://news.ycombinator.com/showhn.html](https://news.ycombinator.com/showhn.html)

> _Blog posts, sign-up pages, and fundraisers can 't be tried out, so they
> can't be Show HNs._

(Disclaimer: I prefer rebasing.)

~~~
jpdel
Ok thanks. Won't post articles as Show HN in the future.

------
11235813213455
It's more that feature branches should be __rebased __instead of merging the
main branch into it (like most developers unfortunately do)

    
    
        [pull]
            rebase = true
    

in your ~/.gitconfig, and just pull the branch your forked from

This way, the git history is linear, clean and readable

~~~
ScottFree
Rebase is so terrible and not because of the lost commit history (most of
which deserves to be lost, imho. git merge history is too verbose and
oftentimes not useful).

My issue with rebase is that as soon as you want a single other person to
commit code to that branch, you can no longer rebase. Everything must be
merged from that point on, otherwise the histories diverge and you wind up in
rebase/merge hell.

The only alternative I've found is to over-communicate every push to your co-
worker because it requires him to stash his changes, delete his local branch,
pull down the "new" remote branch and re-apply his changes.

~~~
pxue
use interactive rebase?

------
turdnagel
Not really a show HN.

Also, rebase master into your feature branches regularly.

~~~
AstralStorm
I recommend pulling instead. That way you do not lose information on when
given code was done and conflict resolution is visible, making hacks like git-
rerere less required and automated merging tools more potent.

This is really important when there are parallel feature branches and even
more so when features are codependent.

E.g. if feature a depends on feature b, if you rebase feature a you cannot
just pull it into feature b as there will be duplicate commits.

If you want nice lines you should hire a painter. If you want easy merges,
merge instead of rebasing.

------
kaelig
One of the issues with feature branches is that long-lived feature branches
easily go stale, and each day that passes by makes it riskier to merge them
into master.

While I agree with the author on the general idea of trunk-based development
(and feature switches), can't we get the best of both worlds by allowing
short-lived pull requests where code review can happen?

I'd be curious to hear from teams here who push directly to master and how
this workflow works for them.

~~~
jstimpfle
Not doing any of this myself, but the keyword here is "rebase".

(But yeah, there's a problem with reduced testing during feature development.
What if a feature branch breaks the main branch and it does not get noted
during feature development? I'd argue if it affects the core then it's not
strictly a "feature")

------
jstimpfle
I guess the main advantage of feature branches is that you can easily drop
them if it turns out the feature was a bad idea or too hard to implement.

The advantage of trunk based development would be that the feature gets
potentially more testing. Same goes for interactions with the main line code -
if feature development breaks the core in subtle ways, it will be noticed
earlier using trunk based development.

~~~
AstralStorm
It will be noticed - by angry users. Which is why untested continuous
deployment is madness.

When you do checkpoint regular releases done often, you get a chance to
smoketest and block a release. Automated smoke tests only go so far in fixing
this - if you could cheaply, reliably and completely fully automate testing,
everyone would already do that.

About the only way to do continuous deployment is to not deploy into
production but use lagged deployment practice...

~~~
jstimpfle
Yes - in my case the "users" are just my colleagues (and yes, they could get
angry, but the feedback can be worth it).

I believe that "trunk" is not commonly meant to be immediately deployed to
users. But, maybe things are different in the web world, where "deploy" is as
easy as "upload to server"?

------
mikekchar
I like TBD -- a lot. However there are a couple of problems with it. If your
team is not collocated in a time zone then you'll one one guy (me, for
instance) who will push 8 hours of development into trunk without anyone else
getting a chance to look at it.

The same thing happens if you have someone who just "disappears" for a day or
two and effectively has a feature branch. You need to have discipline on your
team to push often (I like to push at least every 20 minutes).

I also tend to think that continuous deployment with TBD is risky. It depends
on how good your automated acceptance tests are, but I tend to like to do a
manual sanity check before deployment. It's a lot easier when you are not
working on a moving target.

Finally, sometimes you just _have_ to break something in order to change its
direction. This forces you into a feature branch if you are doing continuous
deployment.

We've occasionally experimented with having an "integration branch" that acts
like trunk but isn't deployed. You can then time your trunk deployments,
potentially cherry picking from the integration branch. It seems like a good
solution, but I've found it to be more trouble than its worth most of the
time.

Having said all that, my preference would be to abandon continuous deployment
and instead have regular deployment (say once a week or once every 2 weeks)
with a mechanism for hot patches. Then force everyone to work mostly core
hours and have continuous integration (with commits coming in every 5 minutes
or so). In my experience this has produced dramatically better results than
feature branches.

However... On my team it is impossible (not least because I'm 9 time zones
away from the majority of my team mates). So feature branches are an
acceptable second best.

~~~
jstimpfle
> (I like to push at least every 20 minutes)

That sounds _extreme_ to me. What kind of development do you do that makes
this possible? I rarely finish something within 20 minutes. Often, I'm
thinking about the right way to do something for a day or longer before I
decide to push some results. (UPDATE, before I even start to write some code!)

~~~
Grue3
I'd even go as far as to say that any code that was written in the span of 20
minutes can't possibly be good code, and doesn't deserve to be in master. The
code quality and commit history must be pretty terrible in a project like
this.

~~~
mikekchar
If you want to see some typical code from me, here are the commits from an
experimental side project:
[https://gitlab.com/mikekchar/testy/commits/master](https://gitlab.com/mikekchar/testy/commits/master)

Some caveats: I was experimenting with a different way of doing OOP in JS.
Here is a description of the design:
[https://gitlab.com/mikekchar/testy/blob/master/design.md](https://gitlab.com/mikekchar/testy/blob/master/design.md)
There is also a coding standard that I was following:
[https://gitlab.com/mikekchar/testy/blob/master/coding_standa...](https://gitlab.com/mikekchar/testy/blob/master/coding_standard.md)
It's not one that I advocate, it was one that I was experimenting with.

Some of the code in there is not great. Some of it is OK. It's not a big
project, but it will give you an idea of the scope I use when I make commits.
I use a very conservative approach when programming -- I don't pull everything
apart and then try to build it back up. Instead I refactor everything and make
incremental improvements. Every commit should improve either the quality of
the code or add functionality. Especially in this project, I was building a
test framework, so I didn't have a test framework to work with. This meant I
had to use an even more conservative approach than normal. However, like I
said it should give you a good idea.

Perhaps you think this is bad code. I don't think it is. It's got a strange
style (because that was the point of the exercise), but generally it was quite
nice to work with. There are 2 pretty nasty hacks that I made in order to get
the framework bootstrapped. I would have improved them eventually, but I ended
up ending the project early. If I were to really criticise my work here, I
would say that my commit messages are pretty awful. Interestingly, the TODO
items that I check off in the actual commit are quite good IMHO. Probably I
should cut and paste them, but... it's a personal project in my spare time...
I was being lazy :-P

I guess I'm responding to your comment mainly to hopefully open your mind to
different ways of doing things. Maybe you'll be able to see it, maybe you
won't. One of the things I've found in this job is that there are a lot of
people who are stuck in "It's either my way or it's crap". Your comment seems
to indicate that you might be one of those people. But in the case you are
not, I hope you'll find the code interesting.

I've worked on small projects and I've worked on big projects (I once "owned"
a million lines of code!). The style I use now evolved based on my
experiences. My basic approach is to look at a piece of code and try to find a
general strategy for what I want to do. If I don't know the code, that can
take a long time, but once I've figured out what I'm doing, things can go
pretty rapidly.

I make a TODO list of what I'm planning to do. Then I look at the code for a
minute or two and ask myself, "Can I get there from here?" If the answer is
"No", then I ask myself, "What would I ideally want?" Then I write that down
in my TODO. Usually it's a fair number of things.

Normally those facilities require pure refactoring (i.e. changing the code in
a way that doesn't change behaviour). I try to break up my challenge in such a
way that I make an improvement to the code, and that keeps the behaviour
intact. Sometimes before I start I need to write tests to document the current
behaviour.

So a typical session would be: Write test(s) that are lacking. Check in code.
Refactor code to provide facility(s) that I'm going to want. Check in code.
Make a behavioral change with tests. Check in code. Then go back to my TODO
list to get the next step.

I _will_ leave "bad" code in the build -- sometimes for a very long time, if I
don't have a good idea for how it "should" look. Even if there is a "good" way
to represent it, I'll often put it off if I don't know that this "good" way is
going to fit with the direction the code is going. Overworking a piece of code
often leads to unintentional inflexibility and sometimes good looking code
adds constraints that you don't need. However, because the code looks good,
nobody will refactor it and remove the constraints, leading to overly complex
code.

If you've gotten this far, you can see some of the challenges for TBD with
this method, though. Every change has to keep the system completely
functional! This means very deliberate and very careful modifications. It's
difficult, but there is plenty of upside. IMHO there is more upside than
downside by quite a margin. YMMV (and I won't tell you that you must be a crap
programmer simply because you do things differently than me ;-) ).

Edit: I went through some of your commits on
[https://github.com/tshatrov/ichiran](https://github.com/tshatrov/ichiran)
It's interesting to me that the commit size is not really that different than
mine. There are a couple of places I would have split it up into 2 or 3
chunks, but we're not talking about order of magnitude stuff here. I'm curious
how long you spend on a commit. Nice project, BTW. I'm not a stranger to
building that kind of tool ;-) I actually built an English parser in FORTH
once. I also built:
[https://github.com/mikekchar/JLDrill](https://github.com/mikekchar/JLDrill)
(which actually _is_ awful code... and it doesn't actually run any more thanks
to bitrot).

~~~
Grue3
Well, I won't judge personal open-source projects (where there's usually only
one contributor) on the same level as large collaborative projects where code
quality and commit history actually matters. Ichiran is not a typical project
because most of commits (especially recently) are "data" commits and not
"logic" commits. I do run tests before every commit, but if there's no
programming logic changes I can bump it into prod right away. Commits that
actually change the logic of the program are tested and dog-fooded locally for
days before I even upload them to github. I also use feature branches for
"big" features so that I can fix bugs in master if I happen to discover them,
while continuing to develop a feature in parallel. Because I don't have much
free time to develop my personal projects, a big feature might take weeks or
months to get merged in, but I'm not in a hurry!

------
kennethh
If one read Martin Fowler about feature branching,
[https://martinfowler.com/bliki/FeatureBranch.html](https://martinfowler.com/bliki/FeatureBranch.html)
and articles from Jez Humble both agree on that one should use trunk based
development and use feature toggles in most cases for development.

~~~
AstralStorm
Sure, do end up with hundreds of commits where any given combination of
feature flags fails, except sometimes the default.

Seriously, this is the quintessential Gentoo Linux problem. Nobody can test
all the combinations making the flags almost instantly useless. (And some
essentially forced on.)

~~~
jpdel
Agree that feature flags count should not explode because you can never test
all combinations. Feature toggles should drive the life span of a feature from
start of development to "adopted and becomes the default" or "rejected and we
scrap it all out". At the end of the day the number of feature toggles should
remain relatively low.

------
tjwds
"Your feature branch is your own perfect garden and you can keep it clean and
shiny. But it is separated from the other gardens of your team. The more you
work apart, the harder it is to reconcile."

But then, later in the article,

"It is 2019. If you don’t have a continuous integration setup that builds and
runs tests automatically … then set it up yesterday. If you break anything
you’ll be notified before it becomes a problem for the whole team."

Which, in my experience, greatly helps to mitigate the "it works on my
machine" factor that arises from having a new branch for each task.

I appreciate the perspective, but I've found working with feature branches
much better than trunk-based development. I'll take my merge conflicts any
day. :-)

------
arnvald
I've tried trunk-based development before, and while it provides certain
benefits, I don't think it's a silver bullet.

> Why you should not use feature branches

> Keep reading, all the objections you can think of are wrong.

The tone of the title and some parts of articles suggests that trunk-based
development is objectively better than feature branches. I feel that it's
rather a matter of opinion. You might want to try it out, it might work better
for you than feature branches. But I don't think saying "feature branches are
wrong approach" or "your objections are not valid" is true for everyone.

One example are code reviews.

> If the code review culture is strong in your team then it can very well be
> done on the commit to the main branch.

Personally I find this inconvenient. Reviewing a single commit does not show
me the bigger picture. Let's say I refactor some code before adding a new
feature. Refactoring is in a single commit, but to see whether this
refactoring makes sense, it's better if the reviewer sees the next step, then
they can understand better why I refactored it in this particular way.

> The main thing to improve here is probably not the branching model, but the
> code review process.

Maybe this is true. Maybe my way of thinking about code reviews is wrong.
However, again, I feel it's a matter of preference. I tried both ways and I
certainly prefer reviewing the whole feature than single commits.

One more problem I find with trunk-based development: it happened to me before
that a developer did something completely wrong. They misunderstood the
requirement, they misunderstood the code - it happens, the world's not
perfect. With feature branch I'll just ask developer to start from scratch.
`git branch -D` and that code is gone. With trunk-based development the code
is already in the master branch, and while it obviously can be changed or
reverted, it's already there, people already have pulled this code, they
modify this code, they look at it and try to understand it, they try to figure
out why it's there.

Again, I'm not saying here that trunk-based development is a bad idea. It
might be working for you, it might not, everyone's different. I believe the
article explains the benefits of trunk-based development pretty well, I wish
though it wasn't presented as an objectively superior alternative to feature
branches.

~~~
jpdel
Fair enough. You have a valid point on "your objections are not valid" is not
the right tone. I'll edit to highlight that feature branches have their
benefits in some cases. Thanks for reading!

~~~
arnvald
Thank you for considering my comment!

~~~
jpdel
I've updated the sentence with "Here are the common objections one might have
and a tentative solution" and extended the conclusion to say "TBD is not the
only way to work"

------
dwyer
I just rebase my feature branches before merging. Keeps the tree more or less
linear.

