Hacker News new | ask | show | jobs
by watt 3185 days ago
The advice here given to avoid using "master" branch for development, and advice to create non-default branch named "develop" (or variations thereof) is quite harmful.

If you must have a "release" branch or "stable" branch, ok, go for it, but leave the "master" for developing. Why? Strive to have sane defaults.

Frankly, the idea that somebody must check out some extra special branch after cloning repo in order to start properly developing, is not sane.

4 comments

> Leave the "master" for developing.

IMHO do developing always on topic branches, never on master.

This keeps master available for fully-working software, such as for the most-recent successful build using continuous integration, or for always-available deployment, or for external users, etc.

To create topic branches, here are git alias commands that you can customize as you like for your git workflows:

    topic-start  = "!f(){ b=$1; git checkout master; git fetch; git rebase; git checkout -b "$b" master; };f"

    topic-finish = "!f(){ b=$(git branch-name); git checkout master; git branch -d "$b"; git push origin ":$b"; };f"

    branch-name = rev-parse --abbrev-ref HEAD
What's the point of running CI on a branch that's effectively for tracking releases only?

We run CI on master branch and fix any build breaks or regressions immediately. (That's the job of unit tests and integration tests.)

In fact, if your team is smaller, you do release from master branch directly, just tag the release revisions. Then if you need to hotfix it, check out the tag, make a branch, cherrypick a fix to the branch, and do point release from the branch: problem solved.

That's if the client running the (older) release version is large enough to justify releasing hotfix instead of doing fix to main stream and just asking to upgrade to latest release.

Yes to topic branches. Yes to "cactus model" of rebasing the topic to master. No to the idea that you need extra long-lived "develop" branch in parallel to master.

> What's the point of running CI on a branch that's effectively for tracking releases only?

I'm recommending using master as the output of a successful continuous integration, and thus always ready for release.

I'm rejecting any git flow that has any developer pushing any code directly to master, while hoping/guessing that master branch integration will succeed.

Caveat: Bugs will still happen.

Caveat: There are more-advanced release processes such as blue/green, alpha/beta, canary/throttle, etc.

Caveat: There are more-sophisticated integration techniques such as an internal private master branch that differs from an external public master branch. YMMV. Use the right tools for the job.)

Caveat: There are more-advanced release processes such as blue/green, alpha/beta, canary/throttle, etc.

What does Facebook do? It's hard to imagine that they slow themselves down this much. They tend to hide features behind feature flags, but is it known what their CI process is like?

Github pushes topic branches to production and if they don't cause troubles then merges to master. The idea is that good state is defined as works in production not just passed CI tests.
> There are more-advanced release processes such as blue/green

Blue/green is actually very similar to the Git branching model of forking release branches off of the development branch to merge them in the master branch, if not precisely the same thing referred by different names.

I was researching some of this a few weeks ago, and there are many posts about tags being a bad idea. The arguments are that they have to be maintained separately and they lack context.

But yes, master branch master race.

Also related: "What are the problems with 'a successful Git branching model'?" https://barro.github.io/2016/02/a-succesful-git-branching-mo...

Speaking of bad ideas, anyone want to weigh in on merge commits? I've seen arguments in favor of using `git rebase` everywhere, both ways, and to never squash commits. This makes `git bisect` usable, since you never run into a situation where it points to a massive commit as the problem.

On the other hand, that seems pretty terrible from a `git log` perspective, since many commits are WIP. But maybe it's not a big deal. My bigger concern is that merge commits provide real context: whenever you merge a topic branch into master, it seems to make sense to have a merge commit for that entire operation. But wouldn't that cause `git bisect` to always point to that merge commit rather than one of the smaller commits?

I always advocate workflows where merges never happen.

To me, the 'git log' of a master branch is like a history book about the repository. When you read through it, it should give you answers to the questions "what was changed, why, and when" in as clear format as possible.

Now, I've read most of the arguments trying to show that merges are the way to do just this, instead of rewriting history with interactive rebasing. I won't repeat them all here, but just want to ask this: when one reads a real book about real world history, does it look more like git log history of a repo which has been using rebase, or merge?

I'm not sold on the idea of the master log as a readable narrative.

If you really want to maintain such a narrative, it would be possible to do it separately, in something like a changelog.

You might even hire someone to do that, a kind of technical historian. It's real work, because software development is pretty messy.

If you reaaally care about the history of the software's development, I would seriously consider aggressive rebasing of the repository even much later -- you could refactor the commit history as much as you want to clarify the logical progression of the software.

As I see it, a source code repository is not like a history book, because a history book is written after the fact by a trained historian who spends a lot of energy on tidying up the narrative and making it actually comprehensible.

A source code repository looks to me more like an archaelogical artifact with some terse notes sprinkled in there as clues by the various workers.

Basically I think the git log structure is kind of overblown and workflow arguments that hinge on the legibility of the repository's graph structure don't really matter that much to me.

I still sometimes write pretty involved commit messages, but that's a kind of separate issue from these "workflow" discussions that are mostly about how you should formally arrange the DAG. And I also know that my commit messages are mostly lost in time like tears in rain, so I try to communicate important changes in other ways.

It looks more like merge. Chinese history and European history merged around 1200, and then again a few centuries later. American history and European history merged around 900 and then again in 1492.

But, why not both? Using interactive rebase lets you keep a clean and bisectable history made of small commits. The developer every now and then can also rebase to master and ensure that all commits pass the tests (and perhaps write more tests based on what happened in the meanwhile on the master branch).

However, when CI runs, features are included in master with a merge commit, so that the occasional semantic merge conflict will bisect exactly to the merge commit and the developer of the feature isn't blamed incorrectly.

> when one reads a real book about real world history, does it look more like git log history of a repo which has been using rebase, or merge?

This is a bizarre analogy. History books are a record of things that happened in the world's timeline, which is in fact linear. Source control is a record of things which happened in the timeline of development, which is typically branched.

Imagine a history book from some terrifying PKD-esque sci-fi universe where timelines branch and re-converge. Does that look more like git log history of a repo which has been using rebase, or merge?

Sure, I agree. But a history book tends to be more substantive than "WIP building a nation", which is what most of our commits look like in practice.

Squashing would seem to be the answer, but do you feel that's a bad idea? It certainly has tradeoffs. You can easily end up with a massive squash commit.

I really want to keep the WIP commits. They provide context even if their log messages don't, and they make git bisect easier. But I don't think anybody does that, and I'm curious why.

My bad, I was going to edit my comment to be less coy and more constructive, but I'll just continue here.

Even though I always advocate rebasing, I also think that WIP commits should not reach master as-is. We are actually using Phabricator with my current team, and they have a really nice opinionated way of doing development. All dev happens usually in (really short-lived) task branches, but once they have gone through review etc. they are landed on master as one single commit, with the commit message holding all the relevant information about the change(s) made in the original task branch.

The reason for not having the WIP commits on master is that "commit early, commit often" is good practice, so the sheer amount of WIP commits will completely drown out the actual, finalised changes (i.e. the "actually interesting history as in a history book") in master. So no, I don't think squashing is a bad idea, I think is absolutely essential if you rebase onto master. If you don't squash, rebasing might lead to more mess than using merge.

Now, as to keeping WIP commits. I think that their value is usually much overestimated. I can count the times I have needed to go back to the actual, raw WIP commits instead of the properly rewritten one in master with one hand. But if you feel that it's the only thing keeping you from switching from merge-intensive flow to a always-interactive-rebase one, I'd encourage you just to retain the original, short-lived development branches in origin as separate branches. IMHO that gives best of the both worlds, if you think throwing out the WIP commits could hurt too much.

---

Edit: oh, and having massive squashed commits should not usually be a problem because mostly they should not happen. Individual tasks should be so small that implementing them can not result in a massive amount of changed lines.

Or most importantly for us, master needs to always work, because that's where you start new development on.

You can't expect to fix another bug somewhere else in the codebase if you are starting from a point where the code may not work, or features may only be partially complete.

I find the idea that master is the default is exactly why it should not be the development branch. For open-source software, that's what people download and try to build -- it should always strive to be production ready.
People should be downloading actual releases. This could be release archives, or release tags.

Version control is not primarily for consumption of releases, it's for participation in development, and I think the branching strategy should reflect that. Having the current development state be the default branch is entirely suitable for this purpose.

I've always found the use of "develop" vs "master" quite jarring, and not even that helpful for an end user. master can change on a whim, while using actual release tags gives you something stable.

> People should be downloading actual releases. This could be release archives, or release tags.

Yes, and those versions are represented by tags created on the master branch. Github automatically interprets tags created on the master branch as being releases, and even creates nice little tar files with the branch's contents.

> master can change on a whim

Actually, it can't. According to the Git workflow, the only thing committed to the master branch is either the contents of release branches or hotfixes.

You can have both. With the right tooling you can prevent direct push to master, but at the same time implement CI to which you can submit your branches to be merged to master.

This way you can develop against master, you won't push garbage into it by mistake, and you can guarantee that each (first-parent path) commit on master passes the automated tests.

I'm assuming you think it's harmful because master is the branch committed to and pushed by default?
Yes, because master is the default implicit branch. (Now, in git is possible to designate other branch as default, but folks who follow the advice in article often are not experienced enough to do it.)

I know a team that runs this branching model. It's quite surprising to hear statements "we never commit to master branch". "after cloning, always remember to switch to development branch". "when creating pull request, always remember if you used "development" as base". and then the mistakes eat up lot of cycles in the end.

all they've done is just rename master.
I don’t think this article gives advice to not use master for development but rather what it means is:

1. master must only have stable, tested, and production (not production “ready”) code and nothing else

2. If something in production breaks the hotfix should go into master and strive to achieve step 1

In fact this is really a good model. Keeps development streamlined and disciplined.

This has nothing to do with breaking the idea of having sane git defaults. In fact it’s a sane utilisation of defaults.

Non default branching is a necessity anyway. Default branch usually means just a master branch and committing directly into master, I believe, would lead to disaster. If one has to create branches it should be done for lifestyle steps below production.