28

I have seen lots of advice about git branching models and the most common opinion seems to be that making changes directly on the master branch is a bad idea.

One of our co-workers is quite happy making changes directly on the master branch, and despite several conversations, they seem not likely to change this.

At this point in time, I can't convince a co-worker that is a bad practice to work directly on master, but I would like to understand the things that will conflict with his way of working, to know when I need to revisit this issue.

Michael Durrant
  • 13,101
  • 5
  • 34
  • 60
linuxunil
  • 1,441
  • 10
  • 17
  • 2
    Define "working directly". Master exists because it's meant to be used. What do you think it's for and what isn't it for? – candied_orange Nov 08 '16 at 20:04
  • 3
    Is working off of master working for you? If it is, why do you feel the need to change right now? If it's not working, what problem(s) are you experiencing? Instead of asking for people to point you to other people's arguments, we can help you solve your problems. – Thomas Owens Nov 08 '16 at 20:16
  • 1
    Sounds like he's doing trunk development, which, along with continuous integration, is pretty normal in an Agile team. If he wants to work like this, you will need to enforce WIP to ensure that there's never too much work going on against one product at a time - and also use feature switching to ensure that master can be released with incomplete features turned off. – Mr Cochese Nov 09 '16 at 10:13
  • ...how big is the team? – ZJR Nov 09 '16 at 12:00
  • 1
    @MrCochese I wouldn't call trunk development in the sense here "normal". Certainly none of the many places I've used Git has worked that way, and I would discourage it. Feature branches just work better. – Marnen Laibow-Koser May 18 '18 at 00:56
  • @Marnen Laibow-Koser That’s a bold claim! Feel free to share your evidence, of course. – Mr Cochese May 18 '18 at 09:17
  • @MrCochese IMHO you're the one making the bold claim, and so the burden of proof is on you. But: trunk-based development of this sort means you can't easily get an accurate history of each feature within the context it was originally developed, and results in a lot of "dead" code making it into releases. There's really no advantage to it that compensates for these disadvantages: it's not hard to keep feature branches current, or for developers to look at other feature branches. Trunk-based development may make sense with SVN, since merging is a pain. Git's easy merges remove this reason. – Marnen Laibow-Koser May 18 '18 at 16:24

8 Answers8

61

There are several problems when commits are directly pushed to master

  • If you push a work-in-progress state to remote, the master is potentially broken
  • If another developer starts work for a new feature from master, she starts with a potentially broken state. This slows down development
  • Different features/bugfixes are not isolated, so that the complexity of all ongoing development tasks is combined in one branch. This increases the amount of communication necessary between all developers
  • You cannot do pull requests which are very good mechanism for code reviews
  • You cannot squash commits/change git history in general, as other developers might already have pulled the master branch in the meantime
Gernot
  • 726
  • 5
  • 7
  • 13
    Hey look! You actually answered the question, unlike basically everyone else. ++ Welcome to SE.SE! – RubberDuck Nov 09 '16 at 10:52
  • 1
    Most of these are problems derived from working directly on master *badly*, not from working directly on master per se. – Ant P May 08 '17 at 11:42
  • 2
    @AntP which problems could be prevented from your point of view? – Gernot May 10 '17 at 07:25
14

Explain to him that new features need their own development branch that can be deployed to a test environment before it is pushed to production.

Otherwise, you're in a perpetual state of half-completed features. You can't deploy half-completed features to production, so if you're working directly on the master branch, everyone else must wait for you to finish your feature before anyone else's changes can go to production, including bug fixes.

Using independent branches for features means that each new feature can be tested and deployed independently of the others.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • *"You can't deploy half-completed features to production"* - this is not true at all - it is entirely possible to work directly on the main branch, ship code every commit, frequently deploy "half-completed features" and never break anything. Continuous delivery is about doing exactly this: decoupling deployment from release. Which also happens to solve lots of other organisational problems that people normally address with half-broken technical solutions. Sometimes this involves feature toggles but usually it's possible to build and deploy 90% of a feature with no visible behavioural change. – Ant P May 08 '17 at 11:46
  • @AntP: The process that you're describing is not what I would call "half-completed features." Such features are either tested, production-ready and usable, or they're hidden by a feature switch or something similar until such time as they *are* tested, production-ready and usable. You're not shipping features that don't work. – Robert Harvey May 08 '17 at 19:05
  • You asserted that new features need to be developed on non-master branches because you can't deploy half-finished ones: that's not the case. You absolutely can develop new features directly on master and ship any and all code related to those features to production before the feature is complete and without holding up other development. – Ant P May 08 '17 at 19:58
  • 2
    @AntP: What I said (perhaps unclearly) was that, if you have multiple people developing on the master branch directly, and you need to ship before one of these people has completed their work, then you need a way to keep the unfinished work out of the shipment build. One way to do that is to not check in your work until it is done, but that's risky. Another way is to have feature switches. The best way (if your features are more than a day's work or two) is to have feature branches and merge each feature branch into the main branch when it is completed. – Robert Harvey May 08 '17 at 22:04
  • But with a little discipline, you *can* keep master rolling forward and unfinished feature work transparent and (commit-by-commit) deployable. That's contrary to the suggestion in your answer that without feature branches everyone has to wait until everyone else is done before anyone can deploy anything. Working this way actually has a lot of benefits - keeps work streams integrated, keeps production up to date, keeps deliveries small, encourages QA and stakeholders to focus on business value instead of code deployments (which should be taken for granted... ) etc. – Ant P May 08 '17 at 22:20
  • 1
    @AntP: In my experience, that can work for very small teams that have the capacity to closely coordinate, and I've worked that way before. So to further clarify, my statement says "don't deploy broken features to the end user." Whatever mechanism you use to prevent that from happening is entirely up to you, but in general, separate feature branches are quite effective in that regard. – Robert Harvey May 08 '17 at 22:24
  • @AntP That's how we used to work on Subversion, because it's branching support wasn't very good. Using Git that way is a big mistake; feature branches provide a much better way of managing this complexity and don't have to preclude team transparency. – Marnen Laibow-Koser May 18 '18 at 00:59
  • @MarnenLaibow-Koser "using Git that way is a big mistake" - that's a very bold comment. You don't have to use explicit feature branching to see the benefit of DVCS and trunk-based development in a DVCS isn't equivalent to using e.g. SVN. In fact, it's the natural conclusion of the "frequent small merges" philosophy and provides many benefits - not least that it does a very good job of encouraging the discipline of small, incremental, non-breaking commits towards a new feature. – Ant P May 18 '18 at 12:49
  • I've worked on many teams that used feature branches and all of them, as maturity grew, tended towards not branching at all, with great productivity - and quality - benefit. Feature branching is a really useful tool when you are accepting pull requests from anyone a la OSS or when your team isn't mature enough for effective single-branch development, though. – Ant P May 18 '18 at 12:51
  • 1
    @AntP Let's not play maturity chicken here. Every team I've worked on, at least, has converged *toward* feature branches (and a pull-request workflow). I don't see how not branching would improve productivity or quality; quite the reverse, since it would result in a lot of half-finished dead code making it into a release. I used to do trunk-based development in SVN. It had no advantages whatsoever over the feature branch workflow I now use with Git. – Marnen Laibow-Koser May 18 '18 at 16:28
  • 1
    @AntP "provides many benefits - not least that it does a very good job of encouraging the discipline of small, incremental, non-breaking commits towards a new feature." Small commits are a good thing. But a policy of non-breaking ones is not. When I create a feature, I *want* the freedom to temporarily break things on my feature branch if necessary. (Broken code doesn't get pushed to a remote, of course.) I do a lot of experimental work as I develop, and that has no place on trunk until the whole feature is ready to merge. I stand by my statement that trunk-based dev is a mistake. – Marnen Laibow-Koser May 18 '18 at 16:33
  • @MarnenLaibow-Koser so branch and experiment locally - that's a tool that's available to you as a developer. But small, master-based commits - *when done right* - provide enormous productivity and risk mitigation benefits and are a natural conclusion of mature development teams - feature branches are a useful tool in lieu of that maturity/as a response to organisational barriers that prevent effective trunk-based development. Key difference between Git and SVN isn't that Git is better for branching - it's that *everything* is a branch (i.e. your local master branch as opposed to the remote). – Ant P May 18 '18 at 18:02
  • My experience of leading software engineering teams has been this: teams with feature branches are like bikes with stabilisers - they will help keep you upright but, once you achieve a certain level of discipline, you'll be a much more effective cyclist without them. – Ant P May 18 '18 at 18:04
  • 1
    @AntP: The one thing that feature branches have that your technique cannot provide is a complete accounting of the work done on a particular feature. In some shops (mine in particular) that kind of accountability is not a luxury but rather a requirement. – Robert Harvey May 18 '18 at 18:15
  • @RobertHarvey - I get that: it's one of the sorts of organisational constraints I was alluding to earlier. That said, there are techniques that can achieve the same thing without the need for branches even if it isn't feasible to educate the business that there are better ways of tracking and auditing software changes that *don't* rely on a brittle coupling of business-level features and physical code changes (which is a tide that is turning in my current organisation to great benefit). – Ant P May 18 '18 at 19:01
  • 1
    @AntP If I understand you correctly, I would consider that a step backwards. I love good issue trackers, and I use them extensively, but I want the VCS to tell me the *development history* of any feature or line of code. The issue tracker can tell the story of the *business* side of a change, but if the VCS can't help me track and audit the *code* by itself, then it's not doing its job. This is one reason I object to trunk-based development: it makes the VCS stupid, for no compensating advantage that I can see. (Also: brittle coupling? A feature *is* a code change.) – Marnen Laibow-Koser May 18 '18 at 19:13
  • @AntP "Key difference between Git and SVN isn't that Git is better for branching" No, it's that Git is better for *merging*. Branching is easy enough in SVN, but merging changes from another branch is hard compared to Git. – Marnen Laibow-Koser May 18 '18 at 19:19
  • @AntP Also, you keep harping on this "mature team" thing, whatever that means. Given the skill sets of myself and my coworkers, I'm quite confident that had we wanted to, we would have been able to do effective trunk-based development at several of my recent jobs—that is, we didn't have any organizational or conceptual barriers that I can think of that would have prevented it, and we were "mature" enough as I understand that concept. But I'm also sure that it wouldn't have been a good idea. It would have led to less code review and more bloat in the codebase. Both of those are bad. – Marnen Laibow-Koser May 18 '18 at 19:25
  • I should mention that I favor a feature branch workflow using small commits and `--no-ff` merges so that each merge has a merge commit and all the commits on the branch are incorporated into trunk/master/whatever. Done right, I believe that this retains the advantages that @AntP claims for trunk-based development, without the disadvantages I claim. [BTW, I am finding this discussion fascinating.] – Marnen Laibow-Koser May 18 '18 at 19:32
3
  • Master should reflect a production branch, a working final version.
  • Working directly in master means that if you create bugs you have no other option for "going back" than to reverse/delete/reset commits, which is not a clean way of working and can cause you to lose the parts of the new code that were OK.
  • Of course, in the very first stages of development perhaps you can begin working directly on master, but after you have something to deliver, you should use development, test or experiment branches to not touch the published, complete, working version.
mcottle
  • 6,122
  • 2
  • 25
  • 27
Tulains Córdova
  • 39,201
  • 12
  • 97
  • 154
3

One of our co-workers is quite happy making changes directly on the master branch, and despite several conversations, they seem not likely to change this.

This leads me to believe there are more issues. Working on master or not is mostly part of a bigger philosophy about how, what and when you release products.

So in tandem with a "you should never work on master", do you have tests of features, do you test each-others work do you review each-others code. Acceptation and integration tests.

If you have none of the above and you're just doing it to "do git", you might as well work on master.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Pieter B
  • 12,867
  • 1
  • 40
  • 65
2

Master should be potentially releasable. Period. There should not be any half finished work in master(unless disabled with a feature flag)

With that said Ive seen some teams complicate their flow.

Not using PR when integrating to master is a mistake since developers will not have the power to choose when integration occurs.

A single development branch brings very little value. Usually it just complicates things. Many feature branches brings much value.

Making branches for each environment(dev, test, prod) is a mistake. This is out of scope for git and should be handled by the release pipeline. The exact same build should be deployed to all environments which is impossible if there are branches for each environment.

If a feature is so big it cannot be done in a day or two all work to a feature branch should be in separate branches and integrated with PR.

Esben Skov Pedersen
  • 5,098
  • 2
  • 21
  • 24
  • I agree with most of what you've said, except for this: "The exact same build should be deployed to all environments". In fact, a release pipeline should generally be able to deploy different builds to different environments and then promote them as tests pass. How do you handle this, if not with different branches (or at least different tags)? – Marnen Laibow-Koser May 18 '18 at 20:05
  • Maybe I wasn't completely clear. Once a build is deployed to an environment. The same artifacts should be deployed to the next environment without a rebuild. – Esben Skov Pedersen May 18 '18 at 21:01
  • If you have repeatable builds, it shouldn't matter whether you rebuild. If you don't have repeatable builds, you've got bigger problems. :) – Marnen Laibow-Koser May 18 '18 at 21:07
  • ...but yes, I do think you should tag your deployed commits so you can promote the same code (regardless of whether you rebuild). – Marnen Laibow-Koser May 18 '18 at 21:11
  • Yes but most CI servers can link builds to releases out of the box making it easy to track deployments. When setup correctly it is not really needed to track deployments in git. Git is a scm. Not a deployment tool. – Esben Skov Pedersen May 18 '18 at 21:52
  • Sure, you could refer to a commit hash, but a Git tag (or branch) makes it easier to have a nice human-readable version number. Also, Git absolutely can be a deployment tool; it works very well for that purpose in some use cases (and badly in others). – Marnen Laibow-Koser May 18 '18 at 22:21
  • Right. I would just advice using the tools for what they are designed to do. IMHO the version number should be inside the repo with the source code. – Esben Skov Pedersen May 19 '18 at 10:08
  • The version number should be on a tag. – Marnen Laibow-Koser May 19 '18 at 15:32
  • If we are using semver, the programmer has to make a decision if (major, minor, patch) should be bumped. This is not something the pipeline knows. Therefore it makes sense to put this in the source so it is always in sync. If we put this in a variable in the pipeline, we cannot build multiple versions with the same pipeline(without manual input) – Esben Skov Pedersen May 20 '18 at 07:49
  • Yes, I agree with that. But it also makes sense to tag the commit that is considered the released version. Look at the typical pattern in a Ruby gem: there are many commits containing "1.2.3" in the version file, but only one of those is tagged "v1.2.3". That one, and that one alone, represents the 1.2.3 gem release. The tag is essential for identifying a particular commit. The version number in the source is merely a nicety. – Marnen Laibow-Koser May 20 '18 at 16:24
  • I think it is the other way around. The version number is in the source because it should follow the state of the source code at all times. If you find value in tagging commit - by all means. – Esben Skov Pedersen May 21 '18 at 07:53
  • Your logic is flawed, I think: the version number in code *can’t* follow the state of the source code at all times, because a version number in the codebase typically stays the same through more than one commit. If you need to refer to a particular state of the codebase reliably, the *only* way to do that is by referring to *one particular commit* — either with a hash or a tag/branch ref. – Marnen Laibow-Koser May 26 '18 at 22:14
  • It is not my logic. If you don't want to work with semver that's fine, but it is becoming an industry standard and my suggestion makes working with semver easier. – Esben Skov Pedersen May 27 '18 at 19:28
  • I am talking about working with semver. Where did you get the idea that I was avoiding it? – Marnen Laibow-Koser May 28 '18 at 14:36
  • When you said my logic was flawed – Esben Skov Pedersen May 28 '18 at 15:58
  • Ah, no, I didn’t mean that. I love semver, but I believe that in order to do it properly, it’s safest to tag each release in the repo (for the reasons I’ve gone into above). The flaw in your logic IMHO is what you said about managing version numbers in the code only, not the practice of semver itself (which I wholeheartedly support). – Marnen Laibow-Koser May 28 '18 at 21:30
2

Other answers have already mentioned various advantages (isolated features, always shippable code on master, etc) for working NOT on master directly.

For me you seem to have a different issue. Obviously you don't have a development process, which is agreed or used by all of your developers (or your developer in question is totally ignoring the process).

Do you have feature branches, which are merged into master or do you have different releases branches as well or do you use a totally different process?

"Don't use the master branch" is not sufficient.

Simon
  • 1,774
  • 12
  • 15
2

First, I want to point out that in git, every pull is quite literally a branching operation, and every push is a merge. The master on a developer's machine is a completely separate branch from the master on a central repo you share, with equal standing from a technical perspective. I will occasionally rename my local version to upstream or something if it suits my purposes better.

I point this out because many organizations think they are using branches more effectively than your colleague, when really they are doing little more than creating an additional name for a branch along the way, that won't be saved in the history anyway. If your colleague is committing features in one atomic commit, it is just as easy to back out as a merge commit of a feature branch. The vast majority of feature branches should be very short-lived and frequently merged anyway.

That being said, the main drawbacks of his style of working are twofold. First, it makes it very difficult to collaborate on an unfinished feature. However, it wouldn't be difficult to create a branch on just those times when collaboration is needed.

Second, it makes review before merge very difficult. On this point, you don't actually need to convince him. You can adopt a tool like github, gerrit, or gitlab, and require pull request code reviews and passed automated tests for all merges. If you're not doing something like this, frankly you are not using git to its full potential, and it's no wonder your colleague doesn't see that potential.

Karl Bielefeldt
  • 146,727
  • 38
  • 279
  • 479
  • 1
    Also pushing of the developers his/her branch machine each day is a good backup. – Ian Nov 09 '16 at 17:48
  • I don't understand your first sencence. I don't see how a `pull` would create a new branch or how a `push` would be a merging operation. Rather, a `pull` is *quite literally* a `fetch` followed by a `merge`! – mkrieger1 Nov 16 '16 at 15:35
  • @mkrieger1 I can easily see how one could consider the local `master` to be a different branch from `origin master`. Technically, they are different branches on two different remotes, each with their own history. – RubberDuck Nov 17 '16 at 00:40
  • @RubberDuck Yes, exactly. With `pull`: Before: two branches potentially pointing at different commits - After: two branches pointing at equivalent commits - No branches created, therefore I wouldn't call it a "branching operation". If any of the two commands, I would call `push` that, because it potentially creates a new branch in the remote. What it does *not* do, is a merge. – mkrieger1 Nov 17 '16 at 18:52
  • @mkrieger1 you need to consider the *direction* of the merge as well. – RubberDuck Nov 17 '16 at 18:54
  • To sum up: The first sentence of this answer would make a lot more sense to me if the words `push` and `pull` were exchanged. – mkrieger1 Nov 17 '16 at 18:54
1

There is no "bad practise" around working directly on the branch. But you have to decide what supports your process best:

Question 1: Should your master represent the current release state of your software? Then you should introduce a global development branch and merge the develop at the end of a release development.

Question 2: Do you want to have a code review process? Then you should have "feature branches" that will be merged into master (or develop, if you have one) via pull requests.

Question 3: Is there need to share intermediate code state to other developers that should not be published into production (or test) yet? That is the the case more than one developer develops a feature. Then you should introduce "feature branches".

oopexpert
  • 769
  • 4
  • 7
  • Tags are a very viable way to represent the state of a code base at release. Git makes it very easy to checkout a specific tag. Makes a dev branch kind of moot. – RubberDuck Nov 17 '16 at 00:42