
GitFlow considered harmful - edofic
http://endoflineblog.com/gitflow-considered-harmful
======
sytse
GitLab CEO here. I agree that GitFlow is needlessly complex and that there
should be one main branch. The author advises to merge in feature branches by
rebasing them on master. I think that it is harmful to rewrite history. You
will lose cherry-picks, references in issues and testing results (CI) of those
commits if you give them a new identifier.

The power of git is the ability to work in parallel without getting in each-
others way. No longer having a linear history is an acceptable consequence. In
reality the history was never linear to begin with. It is better to have a
messy but realistic history if you want to trace back what happend and who did
and tested what at what time. I prefer my code to be clean and my history to
be correct.

I prefer to start with GitHub flow (merging feature branches without rebasing)
and described how to deal with different environments and release branches in
GitLab Flow [https://about.gitlab.com/2014/09/29/gitlab-
flow/](https://about.gitlab.com/2014/09/29/gitlab-flow/)

~~~
mikeash
The obsession of git users with rewriting history has always puzzled me. I
like that the feature exists, because it is very occasionally useful, but it's
one of those things you should _almost_ never use.

The whole point of history is to have a record of what happened. If you're
going around and changing it, then you no longer have a record of what
happened, but a record of what you kind of wish had actually happened.

How are you going to find out when a bug was introduced, or see the context in
which a particular bit of code was written, when you may have erased what
actually happened and replaced it with a whitewashed version? What is the
point of having commits in your repository which represent a state that the
code was never actually in?

It always feels to me like people just being image-conscious. Some programmers
really want to come across as careful, conscientious, thoughtful programmers,
but can't actually accomplish it, so instead they do the usual mess, try to
clean it up, then go back and make it look like the code was always clean. It
doesn't actually help anything, it just makes them look better. The stuff
about nonlinear history being harder to read is just rationalization.

~~~
phs2501
The point of rebasing for clarity, IMHO, is to take what might be a large,
unorganized commit or commits (i.e. the result of a few hours good hacking)
and turning it into a _coherent story_ of how that feature is implemented.
This means splitting it into commits (which change one thing), giving them
good commit messages (describing the one thing and its effects), and putting
them in the right order.

Rather than hiding bugs, usually I wind up _finding_ bugs when doing this
because teasing apart the different concerns that were developed in parallel
in the hacking session (while keeping your codebase compiling/tests running at
every step) tends to expose codependence issues that you wouldn't find when
everything's there at once.

It's basically a one-person code review. And when you're done you have a
coherent story (in commits) which is perfectly suited for other people to
review, rather than just a big diff (or smaller messy diffs).

It also lets me commit whenever I want to during development, even if the
build is broken. This is useful for finding bugs during development as you'll
have _more_ recorded states to, i.e., find the last working state when you
screw something up. And in-development commits can be more notes to myself
about the current state of development rather than well-reasoned prose about
the features contained.

I realize not everyone agrees with it, but I hope I've described some good
reasons why I think modifying history (suitably constrained by the don't-do-
it-once-you've-given-your-branch-to-the-public rule) is a good thing, not
something to be shunned.

~~~
wylee
I agree with you, but _only_ for local commits that haven't been pushed to a
shared repo.

Rewriting local history seems no different than rewriting code in your editor.

Rewriting shared history is (almost) always bad.

~~~
sbov
Does _anyone_ advocate rewriting shared history? Oddly I see this "exception"
a lot in reply to this person but I'm not sure I ever read anywhere anyone
saying rewriting shared history is a good idea.

~~~
cpitman
I think its less people saying you should rebase shared history, and more
people saying you should rebase without realizing shared history matters. Then
some poor confused soul starts always rebasing before pushing/merging and they
mess up their local history and do not know how to fix it.

A lot of git is "magic" to many developers, and the way that rebase works is
certainly one of the features poorly understood.

------
ryanthejuggler
> ...the history of a project managed using GitFlow for some time invariably
> starts to resemble a giant ball of spaghetti. Try to find out how the
> project progressed from something like this...

It's simple. Read backwards down the `develop` branch and read off the
`feature/whatever` branches. Just because the graph isn't "pretty" doesn't
mean it's useless.

In general, I'm starting to dislike "XXX considered harmful" articles. It
seems to me like you can spout any opinion under a title of that format and
generate lingering doubt, even if the article itself doesn't hold water. Not
to generalize, of course--not all "XXX considered harmful" articles are
harmful. They generally make at least some good points. I just think the title
format feels kind of clickbaity at this point.

That said, kudos to the author for suggesting an alternative rather than just
enumerating the shortcomings of GitFlow.

~~~
giulianob
Also this is a problem with Git not GitFlow. In Mercurial, for example, every
commit is attached to a branch so it's very easy to follow where the changes
happened.

~~~
ryanthejuggler
Ironically, for that reason, GitFlow would work better in Mercurial. Go
figure.

~~~
davidism
HgFlow already exists and is actively developed:
[https://bitbucket.org/yujiewu/hgflow/wiki/Home](https://bitbucket.org/yujiewu/hgflow/wiki/Home).
It even goes above and beyond GitFlow and adds generalized streams and sub-
streams. I've never had to use those extra features, but the core model works
well.

------
jaimebuelta
The approach discussed on the article seems to take into account only one
possibility: you deploy master in prod, and it's always considered correct.
That works for small projects, but in my experience, when you have a bunch of
people (let's say 20) pushing code to a repo, you need several levels of
"correctness"

\- branches: Work in progress.

\- develop: Code ready to share with others. It can break the build (merge
conflicts, etc) and it won't be the end of the world.

\- master: This shouldn't be broken. It needs to point to a commit that has
already been proven not break the build/pass all the required tests.

As always, you need to find a balance with these things and adapt to the
peculiarities of your code base and team. I really see them as suggestions...

~~~
mmgutz
I don't agree with master being the production code. It's the default branch
when you clone. I like to keep the production branch on a more explicit branch
so my team knows they're dealing with release code.

~~~
Touche
Why not just use tags?

~~~
simias
You might want to cherry pick some commits from the dev branch into a stable
branch from time to time (security fixes, things like that).

~~~
Touche
Sure, you can do that with tags. Branch off from your tag, cherry-pick your
commits, push and if tests pass create a new tag.

------
chaitanya
I have never understood why people hate merge commits so much. Their
advantages are not insignificant: you know when a feature got merged in
master, its much easier to revert a feature if you have a merge commit for it,
much easier to generate a change log with merge commits, and you have none of
the problems that pushing "cleaned up" histories will have: [https://www.mail-
archive.com/dri-devel@lists.sourceforge.net...](https://www.mail-
archive.com/dri-devel@lists.sourceforge.net/msg39091.html)

The main disadvantage, as the article rightly points out, is that it makes it
much harder to read the history. But that's easily solved with a simple
switch: --no-merges. It works with git-log, gitk, tig, and probably others
too. Use --no-merges, and get a nice looking linear history without those
pesky merge commits.

~~~
realityking
The problem, at least for me, is not the merge commit. They are indeed easily
ignored. The problem is, that I don't want to see a dozen commits fixing typos
or trivial bugs.

~~~
gingerlime
slightly OT, but I wonder if anyone has an answer for this.

We use feature branches and rebase before merging to master (mostly for the
reason stated above - keep things clean and treating the branch as a single
logical unit, not caring about higher-resolution history within the branch).

However, some times, especially since we typically merge on Github from a PR,
it's easy to forget to rebase, or notice that there are more commits. So our
history is mostly clean, but occasionally contain some "messy" commits.

I know we can reset master, but it feels a bit too risky compared to living
with a bit of noise when mistakes happen.

Anyone knows of some way to prevent / alert / notify or otherwise help us
avoid this rather common mistake _before_ it happens?

~~~
hayd
I recommend regularly updating your branch of master via fast-forward. That
way if you are working with a slightly different git history, git will
complain loudly (refuse to update).

This also has the benefit of complaining if someone else has force pushed
(changed history / removed commits) to upstream/master.

Catch it early.

[https://leanpub.com/sanegit](https://leanpub.com/sanegit) (I consult/train on
this in SF/Bay area.)

~~~
gingerlime
I'm not sure I understand how this will solve my problem to be honest, and
unfortunately it's not something we would seek to hire a consultant for.

~~~
hayd
I guess it's unclear what you meant by "mess". Some companies think training
their devs is worthwhile, especially after losing days/work/$ through git
messes. :)

------
ninjakeyboard
You don't need to implement ALL of gitflow - I see it as scalable.

Master should always be latest production code, development branch contains
all code pre-release. That's the core.

The other branches let you scale gitflow - if you need to track upcoming
release bugfixes etc, you can use a release branch. A team of maybe 6 or 7
would likely start to need a release branch. Feature branches at this point
are best left local on the developers repository. They rebase to fixup
commits, and then merge those into develop when they're ready.

If you get into bigger teams - like maybe 6 agile teams working on different
larger features, then you can introduce feature branches for the teams to use
on sprints to keep the work separate.

The issue with gitflow is the lack of continuous integration, so I personally
like to get teams to work only on a develop branch during sprints and use
feature toggles to commit work to the develop branch without breaking
anything.

As I see it, gitflow and CI are at odds and that's my biggest gripe with
integrating lots of feature branching for teams - everyone has to integrate at
the end of the day.

So I believe the model can and should be scaled back as far as possible, using
only develop and master and release as primary workflow branches, introducing
the others when the need arises - doing it just because it says so in the doc
isn't the right approach.

------
LukeB_UK
Anyone else fed up of articles using "considered harmful" in the title?
Especially when it's just that the author doesn't like that thing.

~~~
mayoff
[http://meyerweb.com/eric/comment/chech.html](http://meyerweb.com/eric/comment/chech.html)

------
solutionyogi
So let me get this straight.

He is suggesting to use 90% of what GitFlow suggests (feature/hotfix/release
branches) but doesn't like the suggestion of non-fast-forward merge and
master/Dev and that makes GitFlow harmful? I don't think I agree.

I think having the Dev branch is useful. Consider this actual scenario at my
current workplace.

1\. We have 4 developers. Nature of the project is such that we can all work
independently on different features/changes.

2\. We have Production/QA/Dev environment.

3\. When we are working on our individual features, we do the work in
individual branches and merge in to Dev branch (which is continuously
deployed).This lets us know of potential code conflicts between developers in
advance.

4\. When a particular feature is 'developer tested', he/she merges it into a
rolling release branch (Release-1.1, Release-1.2 etc) and this is continuously
deployed to QA environment. Business user does their testing in QA environment
and provides sign off.

5\. We deploy the artifacts of the signed off release branch to Production and
then merge it in to the master and tag it.

Without the development branch, the only place to find out code conflicts will
be in the release branch. I and others on my team personally prefer the early
feedback we can get thanks to the development branch.

Advantages of an explicit merge commit:

1\. Creating the merge commit makes it trivial to revert your merge. [Yes, I
know it is possible to revert the merge but it's not exactly a one step
process.]

2\. Being able to visually see that set of commits belongs to a feature
branch. This is more important to me (and my team) than a 'linear history'
that the author loves.

We have diverted from GitFlow in only one way, we create all
feature/release/bugfix branches from 'master' and not 'develop'.

Now, don't get me wrong, GitFlow is not simple but it's not as complicated as
author seems to suggest. I think the author was better served with article
title like 'What I don't like in GitFlow'.

------
perlgeek
A reason that we are switching from full git flow to a reduced model
(basically one master branch + feature branches, occasional hotfix branches)
is that git flow isn't compatible with continuous integration and continuous
delivery.

The idea of CI is that you integrate all commits, so you must integrate the
develop branch - build the software, run the tests, deploy it to a production-
like environment, test it there too.

So naturally, most testing happens in that environment; and then you make a
production release starting from the master branch, and then install that --
and it's not the same binary that you tested before.

Sure, you could have two test/staging environments, but I don't think I could
get anybody to test their features in both environments. That's just not
practical.

~~~
briHass
Is this more a limitation of your CI/deployment tools? What we do (not saying
it's the true way) is have TeamCity automatically build both master
(production code + hotfixes) and development branches. Our deployment tool
(Octopus) can just grab a particular release (e.g. 1.1.500=master
1.1.501=development) and send it to the server for testing. Hotfixes would be
committed to master and tested with a build from there.

I guess this does open up the possibility that merging master (with hotfixes)
back into development could cause a regression, but we certainly try to keep
hotfixes minimal and simple.

Now database changes...that's the real pain point. Both master and development
need their own DB to apply changes scripts to. Otherwise, deltas from
development make testing master an issue.

~~~
krisdol
At my last company, that was 60 live feature/bug branches, each having to be
built by CI before being mergeable. The feedback loop was huge, and at the end
of the day, the quality of the product did not improve over SVN. develop was a
shit show and twice a month, master would be as well.

Ultimate they decided to move to team branches, where each team branch was
free to operate how they want so long as the team branch itself built
successfully before merging into master. I think most teams adopted the more
natural-feeling GitHub Flow.

Personally, for me it's not even the god-awful history that makes me despise
gitflow, but its reliance on additional tools to effectively manage the
process. This should be a huge red flag to anyone seeking to change a process,
and it's complained about a lot. Cowokers not knowing what git-flow is doing
under the covers is dangerous. I consider myself pretty versatile with git at
this point, but I have no idea what the tool does under the covers. I'm sure I
could find out; however, when you're handed a piece of software, generally you
learn the contract/api it provides, but most of us aren't going to delve into
the implementation details.

------
nijiko
Do what is easiest for you.

1\. Merging vs Rebasing

Open source projects should stick with Merging over cherry-picking and
rebasing especially if you want others to contribute. Unless you feel fine
doing all of the rebasing and cherry-picking for them. Otherwise, good luck
gathering a large enough pool of people to contribute. Simplicity always wins
here.

2\. GitFlow vs X

Once again do what is good for your company and the people around you. If you
have a lot of developers having multiple branches is actually /beneficial/ as
Master is considered ALWAYS working. Develop branch contains things that are
ready to ship, and only things that are READY TO SHIP. So if your feature
isn't ready yet, it can't go to develop, and it won't hit master. Your
features are done in other branches.

3\. Rewriting history

Never do this. Seriously, it will come to bite you in the ass.

4\. Have fun.

Arguing is for people who don't get shit done.

------
jacobparker
> I thought it was a weird, over-engineered solution to a non-existent
> problem.

To be fair, its a cookie-cutter approach that resonates with people unfamiliar
with git but not ready/willing to invest the time to understand it deeply.
That is understandable; a lot of people come from other systems and just need
to get going right away and gits poor reputation for command-line consistency
etc. is well-earned.

(To be clear, I am not a fan of git flow.)

If anyone is interested in truly understanding git, start here:
[http://ftp.newartisans.com/pub/git.from.bottom.up.pdf](http://ftp.newartisans.com/pub/git.from.bottom.up.pdf)

~~~
matthiasv
His point is that this cookie-cutter approach is more complex to the
development model he presents (and is in fact pretty common among open source
software). You don't need to understand Git deeply to realize that master is
stable and merges in finished and cleaned up features.

~~~
jacobparker
I should have been more clear - I agree that its more complicated. My point
was that regardless, it seems to resonate. I believe its because the
complications look useful at a glance and layering a rigid model on top of git
frees you from having to consider its full scope of possible operation.

(I believe that git flow is definitely better than "everyone does things their
way", and that's one competing "rule-book" for a team new to git.)

I'm pretty confident that understanding the tool better will help you to judge
how to use it more effectively. The best way to understand git is to
understand its data-model.

------
omouse
The only thing GitFlow had going for it is that it has a clearly written
article about it with pictures that explain how it works. That's it; the
freedom of git and being able to define what works for you is too much for
people and they think they need to turn development back into Subversion-style
or desktop-release style.

~~~
ryanthejuggler
I agree with you, with one addition in GitFlow's favor--it standardizes how
your team works. When you have multiple team members collaborating on a
project, a poor standard is better than none at all.

------
gouggoug
GitFlow is also in my opinion a bad flow as it does end up with a merge commit
spaghetti over time.

Merge commits are great. They are here to group a list of commits into a
logical set. This logical set could represent one "feature", but not
necessarily. It is up to you to decide whether commits A B C D should or
shouldn't be grouped by a merge commit. Merge commits also make regression
searchs (i.e. git bisect) a lot faster. And to top it of, they will make your
history extremely readable, but that is granted you merge correctly... and
that is where git rebase and git merge --no-ff come into play.

At my company, every developer must rebase their topical branch on top of the
master branch before merging. Once the topical branch is rebased, the merge is
done with a --no-ff. With this extremely easy flow, you end up with a linear
history, made of a master branch going straight up and only everyonce in a
while a merge commit.

Our commit history looks like this:

    
    
      *-------------*---------*---------*----------*----*------->
       \-----------/          \---------/           \--/
    

Following the simple rule "commit, commit, commit..., rebase, merge --no-ff"
avoided the merge spaghetti a lot of people compain about. Although, I have to
admit our repository is small (6583 commits to date).

This works even when multiple devs work on the same branch: they must get in
touch on a regular basis, rebase the branch they are working on and force push
it. Rewritting history of topical branches is only bad if it is not agreed on.
As long as it is done in a controlled manner nothing's wrong with it.

Another rule we follow is to always "git pull --rebase" (or git config
branch.autosetuprebase=true).

Our approach might not, however, scale for larger teams or open source
projects.

------
nsfyn55
I have had this ideological debate about "fast forwarding" more times that I
can count. I agree with the author "no-ff" is silly. I've been working on
professional software teams for over a decade. When I encountered fast
forwarding/rebasing it was absolutely a breath of fresh air. I've been using
git now for 5 years and I have not encountered a single instance where using
either of these tools has presented any sort of problem. I can't remember a
week where having a concise, readable history hasn't proven its value. I also
can't remember a single time I've said "Man I'm glad I had all these merge
commits around they really saved my proverbial bacon"

From what I can tell no-ff exists to satisfy the aesthetic preference of your
local team pedant. It gives them something to do between harping on whether
your behavior is in the correct "domain", deciding if a list comprehensions
are truly "pythonic", and spending that extra month perfecting the event
sourcing engine to revolutionize the "contact us" section of your site.

~~~
JanezStupar
Because you do not need something, then it has to be useless.

> From what I can tell no-ff exists to satisfy the aesthetic preference of
> your local team pedant. Incredible irony.

~~~
nsfyn55
well can you provide the killer use case that none of us can live without?

I mean its certainly possible that in some tiny fraction of cases I might say
"man I could fix this a lot easier if I had the merge commit" its just in the
10,000's of examples that form my experience I haven't stepped on that
particularly landmine yet.

Even with that said, my development philosophy compels me to choose
"Simplicity over Completeness" and is utilitarian to the core. I will chose
whatever is most effective in the vast majority of cases.

Some folks look at "Source Control History" as some pristine, historical
record of how things went down. Since I am not an accountant or auditor this
has little value to me. It encumbers the day to day to optimize for a case
that is almost certain to never happen. A first-order approximation of the
history that optimizes for the day-to-day needs of an organization is far more
suitable in almost every case.

I use the term "local team pedant" its not a bad thing. Some folks just have a
need for things to be "complete" and feel compelled to do so for
irrational(usually expensive) reasons. In my own experience the person that is
the "no rebase/ never fast forward" cheerleader can never give a solid
objective answer as to what the benefit is. Its usually always something like
what this no-ff-er suggests([http://walkingthestack.blogspot.com/2012/05/why-
you-should-u...](http://walkingthestack.blogspot.com/2012/05/why-you-should-
use-git-merge-no-ff-when.html)) . Things like "I can see whats on a branch,
etc." That in itself is not a justification. Its just words. If you could
someone how demonstrate how this reduces development costs or offers a better
way to organize work and is simultaneously better than the more idiomatic
alternatives then I'm all for it.

~~~
JanezStupar
The killer use case for me is getting to figure out how and when something
happened.

Also merging two branches that tend to touch upon same modules but are not
kept in sync all the time (due to whatever reasons) is a lot simpler when you
use --no-ff.

You say that these properties are bullshit, but I found them invaluable when
fixing bugs and architectural defects and where it was important to find out
when and how the bug or a behaviour occurred. And funny that you mention
accountants and auditors. Because being able to do forensics more easily on
the codebases that I worked on has saved me and my clients many hours and gray
hair. And I have found myself in situations where

I can live without --no-ff, I can live without git even. There is plenty of
people out there not using any kind of source control and they are living just
fine.

Your last paragraph is a nice example of psychological projection. If you
weren't so narrow minded you could have used your energy to learn something.

Myself I use --no-ff because it fits the kind of work I do very well. I
haven't lost a minute of sleep or time over its deficiencies. And I am pretty
certain that I spend a whole lot less time fiddling with git than people who
advocate "agressive rebasing".

I do admit you have some merit in pointing out how bad a git history looks
when littered with merge commits for single commit branches. But then, this is
pretty easy to fix. Just use a fucking vanilla merge, or indeed a rebase when
it fits the problem. Another way to work around the bad aspects of --no-ff
approach is by using a better git history explorer.

~~~
nsfyn55
I never said it was bullshit. I'm just looking for your "falsfiability"
criteria. My point is "no-ff" is cluttery and no one can tell me in "objective
terms"(e.g. newtons, projects/year) backed by clear evidence that there is any
benefit. All I see is downside. Your points are pretty shakey lets break them
down shall we?

> Your last paragraph is a nice example of psychological projection. If you
> weren't so narrow minded you could have used your energy to learn something.

well thats clearly ad hominem nonsense. So nothing to see there.

>Myself I use --no-ff because it fits the kind of work I do very well. I
haven't lost a minute of sleep or time over its deficiencies. And I am pretty
certain that I spend a whole lot less time fiddling with git than people who
advocate "agressive rebasing".

No point to any of that either.

>Also merging two branches that tend to touch upon same modules but are not
kept in sync all the time (due to whatever reasons) is a lot simpler when you
use --no-ff.

This might have some merit. But I don't really understand what you mean.

>You say that these properties are bullshit, but I found them invaluable when
fixing bugs and architectural defects and where it was important to find out
when and how the bug or a behaviour occurred. And funny that you mention
accountants and auditors. Because being able to do forensics more easily on
the codebases that I worked on has saved me and my clients many hours and gray
hair. And I have found myself in situations where

Here you actually makes some points but they are all anecdotal. How many hours
has it saved you? How could you even know this unless you split time into two
parallel experiments and measured them independently? Its not that there is
anything wrong with relaying an anecdote. But when you introduce this
handwaving nonsense as justification for something as though it has the same
strength as an objective measurement that I call bullshit.

>I do admit you have some merit in pointing out how bad a git history looks
when littered with merge commits for single commit branches. But then, this is
pretty easy to fix. Just use a fucking vanilla merge, or indeed a rebase when
it fits the problem. Another way to work around the bad aspects of --no-ff
approach is by using a better git history explorer.

After all those words here you start to make some sense. Of course I would use
`no-ff` if I saw some value in a "merge commit" which is the mirror to your
point. But my point is just that ... I've never encountered that case or had
it concisely explained to me

------
Mithaldu
I adore every person who advocates a mostly linear history and is able to
elucidate that efficiently and elegantly. :D

~~~
ionforce
Me too. I'm on team linear history and I still haven't gotten off my bum to
make an article/presentation about it.

But I'm with you, brother!

~~~
nsfyn55
+1

------
orbitur
I can distill my thoughts down to this:

The time it takes to carefully rebase a branch onto another, and to compress
commits for a feature into one, is still much longer than the time it takes
for my eyes to pass over so-called "empty" merge commits.

If I want to look at when a feature entered a branch, I can look at its merge
commit. And the feature branches are there to show how a feature was built;
bugs could be the result of a design decision that happened in one of the
midway commits.

I looked at OP's example pic in the blog, and I read all of his words, but I
wasn't sold. His picture looks like a normal git history to me. It requires
almost no effort to find what I'm looking for.

And that's not even touching his rage against the idea of a canonical release
branch (master). But that's for another day.

------
rattray
I actually thought GitHub Flow was more commonly used, as it's lighter-weight:

[1] [http://scottchacon.com/2011/08/31/github-
flow.html](http://scottchacon.com/2011/08/31/github-flow.html)

[2]
[https://guides.github.com/introduction/flow/](https://guides.github.com/introduction/flow/)

------
talles
I second the feeling of GitFlow being over-engineering:
[http://blog.talles.me/that-git-flow.html](http://blog.talles.me/that-git-
flow.html)

~~~
CrystalGamma
little typo: vMAJOR.MINOR.PATH => vMAJOR.MINOR.PATCH

And I must say I agree with all you say in that post.

~~~
talles
A downside of always typing, never copying and paste.

Thanks!

------
juandazapata
It's not confusing, maybe it's not suited for your particular case, as any
other tool. There's no magic tool/process/etc that does it all for everybody.

GitFlow has been working great for us. A team of 15 developers, working with
feature branches, we have our CircleCI configured to automatically deploy the
"develop" branch to our "QA environment", and our "master" branch to
"production" environment.

The "hotfix" and "release" are proven to be useful to us too; we just need to
have effective communication with our team, so everybody rebase their feature
branch after a merge in our main branches.

------
menssen
I have come to actually like the two permanent branches approach. I know that
for any repository that follows this model that:

* "master" is the current stable release

* "develop" is the current "mostly stable" development version

The first time you clone a repository this is an extremely helpful convention
to quickly get your head around the state of things.

If you're doing it right (and don't use --no-ff, which I agree is
unreasonable), I can't think of a scenario where this causes extra merge
commits. Merges to master should _always_ be fast forward merges.

~~~
jives
We follow this model. I like thinking of "develop" as an integration branch,
and "master" as an always-deployable gold master. And yep, develop -> master
merges are _always_ fast-forward merges.

------
mcv
Advising rebasing over explicit merges is dangerous and foolish. Rebasing does
have its place, but you really need to know what you're doing.

Also, I don't see his point about that messy history. I can see exactly what
happened in that history (though the branch names could have been more
informative). With multiple people working on the same project, feature
branches will save your sanity when you need to do a release, and one feature
turns out to not be ready.

------
jedbrown
Git-flow indeed has serious problems. This author is proposing a particular
subset of gitworkflows(7).

[https://www.kernel.org/pub/software/scm/git/docs/gitworkflow...](https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html)

I like subsetting gitworkflows(7) because you can incrementally add process
when the tangible benefits (like increased reliability and experimental access
for eager users) outweigh their process cost (which depends on team
experience). I wrote about these issues here:

[http://mail-archive.com/search?l=mid&q=87zjx4x417.fsf@mcs.an...](http://mail-
archive.com/search?l=mid&q=87zjx4x417.fsf@mcs.anl.gov)

This diagram represents a workflow that uses 'maint', 'master', and 'next'
branches.

[http://59A2.org/files/simplified-
gitworkflows7.svg](http://59A2.org/files/simplified-gitworkflows7.svg)

------
btreecat
To me (a mercurial user mostly) this is kind of like a "no duh" article having
never read the original "gitflow."

I think that is because I am used to using hg's branches, bookmarks, and tags
for different use cases.

If I want to mark a revision as a particular release number (which is
something we don't really do here but I can see the value) then I would use hg
tag. Tag's are permanent.

If I want to mark a revision as "production" and then have some automated
process take over based on the the updated info, I would use hg bookmark.
Bookmarks are the closest equivalent to git's branches. Bookmarks can be
updated to a new revision or removed.

If I wanted to work on a parallel branch of development for an experimental
feature or if I am attempting to upgrade some dependencies, I can use hg
branch. This creates a named branch in the code base which is permanent. This
branch can eventually be either closed or merged back into the main.

------
nycticorax
It seems like one of the ironies of git-flow is that it would actually work
better if you used it with Mercurial rather than Git, because Mercurial stores
what branch you were on when you made a commit. This means that a tool could
automatically look at the Mercurial commit tree and figure out which swimlane
each commit belongs in, and use this information to draw a commit history tree
that wasn't such a mess.

I apologize for the self-promotion, but this answer on Stack Overflow (and the
question) talks about this difference between Git and Mercurial, and includes
links to articles that explain it better than I could:

[http://stackoverflow.com/a/26784550/1013442](http://stackoverflow.com/a/26784550/1013442)

------
mpdehaan2
Posted a link to this prior blog of mine in article comments also -
[http://michaeldehaan.net/post/116465000577/understanding-
whe...](http://michaeldehaan.net/post/116465000577/understanding-when-to-use-
git-rebase) \- but I'm a huge fan of rebase and topic branches.

One main branch is great, and also if working with a large number of
contributors I really like a clean history, and makes things much easier to
review.

It's kind of a shame something got branded with a slick name like "GitFlow",
when "doing it the way you ought to be doing it" doesn't have a slick name :)

------
rdsubhas
A single eternal master works for a Continuously Deployed app/site.

Not for _any_ other project where maintenance releases are a norm. This
includes stuff strict API compatibility projects, semantically versioned
frameworks/plugins/libraries, many forms of desktop/offline apps, some android
apps, most enterprise apps, etc - more or less where developers don't have the
liberty to thrust the latest master on their users.

I'm not against CD, and not a big fan of Git Flow either. But different things
have their own uses. I'm really liking GitHub Flow and GitLab Flow though!

~~~
habitue
Right, when you need to maintain (and patch) old versions of a piece of
software, having eternal release branches is necessary. The fixes on those old
versions often don't ever want to be merged back to master because the code is
very different in more recent versions.

------
Touche
> All other branches (feature, release, hotfix, and whatever else you need)
> are temporary and only used as a convenience to share code with other
> developers and as a backup measure. They are always removed once the changes
> present on them land on master.

From an open source developer's perspective I need more "eternal" branches
because I need to plan future releases. Putting everything into master makes
the decision for me (if I have a breaking change I have to bump a major
version even if maybe I want to delay doing that).

------
songshu
I wish GitFlow had not called that branch "master", and had called it
"released" or "production" instead. It's really useful to have a branch which
you know always exactly represents the code running in production. You can
keep an IDE pointed at somewhere and update when you need to without worrying
about tags or whatever. This is the one part of it I've tried to sell to
colleagues, which would have been easier if it had a better name.

------
pskocik
I think he makes a valid point about how it's not necessary to have both
develop and master if you use tags. On the other hand, I think the `--no-ff`
merges is what git-flow got right. The separation of features into their own
branches is useful. It's basically about grouping related commits together.
You can always render the history in a way that looks prettier and even if you
can't--the history doesn't need to look pretty, the final product does.

~~~
ionforce
I disagree with you that the history doesn't look pretty.

Have you not found the ability to investigate/audit bugs hindered by non-
linear histories?

------
scottious
I don't see why there has to be "this is harmful" and "this is a better way".

I've used all kinds of branching models... I've used just a master branch and
you commit directly to master. I've used full git-flow.

I think the branching model you use is dependent on the people and the
project. But really no matter which model I've used it seemed to me to be
fine... And if it wasn't fine, we extended it to meet our requirements.

------
Anderkent
Most of the merges in his first pictures aren't even fast-forwardable, so his
complaint about no-ff seems.. weird?

You should still rebase your feature branch on top of whatever you're merging
into whenever you can, even if you're using git-flow. That's just common
sense. When you do, your history looks almost the same as in his 'pretty
graph', there's just one more 'link' back to the previous feature merge.

The advantages of this additional context are important. Firstly, you can get
a compressed view of only the features that were merged (without detailed
commits) with something like `git log --first-parent`. I guess the only way to
do that in OPs approach is `git log | grep 'SPA-'`? Rather... unreliable.

Using no-ff also means you don't have to do the silly thing of putting your
issue name / branch name in every commit title. Titles are pretty short
already, having to allocate ~10% of it to tracking the name of the branch is
just wasteful. With no-ff it's obvious which feature the commit is for (the
branch name in the merge). If your tool fails to present that in a reasonable
fashion, that's disappointing, but the data includes this context and that's
the most important thing.

As to the master/develop split, yeah I could be convinced it's unnecessary.
Still, I think it's convenient to have a clear separation of 'this code is in
production', 'this code is in development'. If you just make a release branch
then merge it into develop, you have to know the exact tag before being able
to find the latest release. 'master' being the alias for 'latest release' is
fine.

------
tokenizerrr
I like to be able to (temporarily) revert an entire feature branch, which
merge commits help with. Is there a way to easily do this without them?

~~~
Mithaldu
If i understand you right, you want to do this:

    
    
        - Checkout master.
        - Start an interactive rebase of master onto the last
          commit before the series of commits you wish to remove.
        - Mark all the commits you don't care about as "skip".
        - Let the rebase run and resolve conflicts on the way,
          the same as you'd do with your current work flow.

~~~
tokenizerrr
This rewrites history, right? What I meant was a feature branch which got
merged into master turned out to introduce unwanted behavior, so while a fix
is rolled out to the feature branch I'd like to remove that code from master.
What I currently do is revert (git revert, which generates a new commit) the
merge commit(s) used to bring that feature branch into master, then when the
fix on the feature branch is complete I revert the revert I just made and
merge the feature branch again.

~~~
Mithaldu
You introduce explicit revert commits?

~~~
tokenizerrr
Yes, this is a feature of git: [https://git-scm.com/docs/git-
revert](https://git-scm.com/docs/git-revert)

I don't think rewriting the history of public branches is a good idea.

------
dankohn1
We use a more extreme version of rebasing feature branches before merging into
master: we squash the features into a single commit when merging to master.
The reason is that we don't care about the (sometimes hundreds of) commits
that made up a feature. What matters is that it works as designed and passes
tests. If we merge a feature to master and then need to revert it, we will
revert the whole feature.

This also allows us to keep merging master into feature branches, (where there
is only a single commit that might need to be manually merged) instead of
rebasing feature branches on master (in which case it can be necessary to
manually merge multiple intermediate commits).

What cleared up git merge --squash for me was a comment showing that:

    
    
      git checkout master
      git merge --squash feature
    

is the equivalent of doing:

    
    
      git checkout feature
      git diff master > feature.patch
      git checkout master
      patch -p1 < feature.patch
      git add .

~~~
Thrymr
That loses a lot of information, though. If you want to bisect to find a
particular bug, tracking it down to the merge is a good start, but I'd rather
have the actual commit (from the maybe hundreds) that went into the merge.
Sure, you can revert the feature, but what if you want to fix the bug?

Git history has a lot of commits. That's OK.

~~~
dankohn1
Yes, the downside of a much more streamlined commit log is that we do throw
out information.

------
radicalbyte
I see GitFlow as a pragmatic workflow customized to cloud-based software.
Master is auto-deployed, and Dev acts as insurance.

We're currently having lots of success with this:

* Always work in a feature branch. * Pull master + rebase feature branch when done. * Merge to master with --no-ff --edit and include a summary.

Rebasing feature branches keeps them readable and avoids continuous merges.
Disable fast-forward keeps the log for /master abstracted to feature-level,
but the details are available in the graph.

Major releases are branched, minors (bugfixes) are tagged. Bugfixes are made
in master and cherry-picked into the release where possible.

Currently our CI build only works on /master, but in the coming month it'll
build all feature branches which have been pushed to the main repository.

This is very similar to how Perforce streams work, but it's distributed. If
you really hate distributed version control and love GUIs then I can recommend
Perforce.

------
jwr
That's the first time I heard of GitFlow. People seriously do software
development this way? I find that hard to believe.

What the author describes is fairly close to what I've been using in a number
of companies now for the last 9 years or so.

Whether to rebase is a personal preference. I tell developers to always rebase
local work before committing. Unobserved changes might as well not exist (if a
tree falls in the forest and no one is there to hear it falling, does it make
a sound?), so if you haven't pushed your work, rebase it. No one cares _when_
you did the work.

As for feature branches, it depends. If the history is clean and there aren't
too many at one time, we might merge without rebasing. But I still prefer to
clean up the commit history and rebase. I don't understand the obsession with
"true history". History is written by victors, in this case — resulting
work/code.

------
JulianMorrison
The whole point of hotfixes is that they are relative to _old_ code and that
they _alter what is considered the current version of that old release_. Which
is important when (as is typical in business) you have customers who are on
specific releases and either haven't paid for the new hotness, or haven't
integrated to it and don't yet want it.

So absolute minimum you need one persistent branch per old release, if you
ever hotfixed it and still have it deployed in the field. GitFlow falls over
here, because it only has one master. But at least it does recognize the fact
that repairing released code is different from pushing the unreleased state of
the art forward.

------
Finster
I can count on zero hands the number of times I've needed to solve a problem
by navigating the branch tree.

I've lost count of the number of times that two eternal branches and feature
branches with pull requests (+ code review) has saved major flaws from getting
to production.

The develop branch is perfect for automatically deploying our bleeding edge to
our test server.

Although, if we move to a more continuous deployment approach, we may
transition away from two eternal branches. But when GitFlow was first written
about, continuous deployment really wasn't the trend that it is now.

Methods will continue to evolve...

------
uzero
Writing considered harmful posts is considered harmful - I hate these so much.

------
leni536
I never used gitflow so I could be wrong but the main problem with logging
seems to be this:

Gitflow thinks about branches as lanes. Git branches are actually labels.
What's the difference? In the gitflow model _every_ commit belongs
(implicitly) to a branch (or a lane). Git branches don't work that way. One
could actually implement "lane" as an additional commit metadata and tweak
git-log (and other git utilities) to always show lanes in straight lines in
the graph.

------
5outh
On the main project I'm working on, the reason we have develop/master is
mainly for hotfixes.

We deploy once a week, but if we need to get something out the door quickly,
we make a hotfix branch off of master, then merge it into both develop _and_
master. This way, if we find something that needs to be fixed before the next
release, but don't want to push half-done updates, we can seamlessly do it.

------
Bahamut
One thing that bothers me about GitFlow is that it mangles history with
merges. Sometimes it becomes tricky to debug issues when history was created
with GitFlow.

I would rather branch off of master, bring changes in via git am or rebasing
when ready, then tag a release when it is ready to be released. If there is
something wrong with master, the tagged releases serve as easy points to
branch off of.

~~~
pacquiao882
I think it depends on the project's structure and team discipline. I tend to
prefer straight lines in the history where a single feature or a group of
similar functions are linear.

------
t_fatus
I think it greatly depends of the size of your team: if you're alone you have
one branch, if you're two you may have 3 branches, each for one of you +
master, if you're four you start to use feature-based branches..

It might be fun to compute the number of branches needed as a function of the
number of devs in your team.

------
mml
Ever since I started getting involved in SCCM stuff, I've been astounded at
how much breath and emotion people are eager to waste defending their choice,
or technique or strategy or whathaveyou.

SCCM system discussions should be banned on HN, as pointless and heated as vi
vs. EMACS discussions.

------
erikb
It's not really harmful just because it's too much overhead for small
projects. If you have a huge project I'd assume that it's much harder to read
history anyway, and then a more complex pattern of development is reasonable.

------
dicroce
Even though I could frequently commit on feature branches, I usually don't.
Hence, when I merge feature branches I don't have crazy messy histories that I
feel it necessary to rewrite.... Works for me.

------
jguegant
What about using merging when it comes to the feature branches but rebase when
pulling (git pull --rebase)? Is it that harmful to rewrite the history for
your local changes?

------
darylteo
Curious here: has anyone tried using GitLab + forks to replace development
branches? Would it needlessly overcomplicated?

~~~
sytse
You can do it but at GitLab we advise against it if you can avoid it. Many
things become harder, for example it is more work to to link merge requests to
issues and you can't push a commit to help a person without them giving you
access first.

~~~
lgp171188
If you are using the Integration-Manager workflow (which GitLab doesn't
support as well as Bitbucket or GitHub), all the members of a team have read
access to all the repositories and forks in the team namespace. That means the
owner of a developer branch fork can always read the repo of another
contributor and pull the changes.

~~~
sytse
Please let me know what you think we should improve to support that workflow
better.

Anyway, I think my examples are still valid, it is harder to mention issues
and you can't push (write) commits on forks since your have read permissions.

~~~
lgp171188
I have already created a feature request here -
[http://feedback.gitlab.com/forums/176466-general/suggestions...](http://feedback.gitlab.com/forums/176466-general/suggestions/8483233-support-
integration-manager-workflow-which-is-avai)

The main assumption in the Integration-Manager workflow is that code from
repositories of other users is always pulled by the owner of the current
repository as and when appropriate.

So if dev1 and dev2 are working on the same feature in 2 different forks of
the main repository, dev1 has to pull commits from dev2 that are needed in
his/her fork and dev2 has to do the same in his/her fork. Once the feature is
complete, the merge request is created from one of the 2 forks.

Yes it is harder to mention issues, but that can be done in the message of the
merge commit. Since forks are essentially equivalent to branches in this
workflow, I usually don't mind referring to issues in the individual commits
itself which would link to the correct issue on getting merged to the main
repository.

We do this with our team's projects hosted on Bitbucket, ymmv.

~~~
sytse
Thanks for leaving a feature request, I commented there.

------
dimino
I personally find git flow to be a wonderfully elegant and simple way of
handling a project in git. Not everything is perfect, but I consider git flow
to be much like PEP8. It's almost always a good idea to do it the git flow
way, unless you have a very specific and documented exception, in which case
do that instead.

To me what matters more is the consistency.

Also, the attitude and tone of this article straight up stinks.

