11 ms·
A simple git branching model
- the1 13y agodo you rebase before accepting pull request or before publishing your feature branch?
- _prometheus 13y agoDepends on how you want to do it. I'd rebase on top of master before publishing, _and_ before merging it in (accepting PR). Definitely be comfortable with rebase before you try this though.
- dexen 13y agoFWIW, this branching model works for me in a small-ish team, two years now and counting. The part about `good merge bubbles' is especially important for clean history.
- Systemic33 13y agoI get an error loading the page, can anyone mirror? "The page isn't redirecting properly" EDIT: I resolved it by going to github.com and signin, and then click link. Shouldn't one be able to look at gists without logging in?
- gizzlon 13y agoworks for me now
- praptak 13y agoI would also add "commit often, squash later". I find frequent local commits useful for quickly rolling back mistakes but they'd just clutter the main history if they got there. Usually if a commit is important enough to end up in master, it is also important enough to do the merge so most of my changes are actually 1 commit (2 if you count the --no-ff merge.)
- chmike 13y agoLearning git here. Could you please explain how rebase squashes commit ? Looking at man git-rebase it seam that it detaches a branch and attaches it to the current branch. From the documentation the chain of commits is preserved and simply moved in the graph. The sequence of commit nodes of the branch are not merged into one commit node.
- crististm 13y agoIf you work on a feature branch originating from master, what you do is "git rebase -i master" to squash your commits.
- Ygg2 13y agoIf you use rebase interactive like this: git rebase -i HEAD~n Where n is number of commits from HEAD, you can do ANYTHING to your branch. You can stop mid rebase to add some files that didn't exist before, squash, fix, execute commands, etc. You can even change order of commits and delete commits from history. BE VERY, VERY CAREFUL! https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html https://www.kernel.org/pub/software/scm/git/docs/git-rebase.... (See interactive mode and splitting commits).
- praptak 13y agoIn addition to the other responses (i.e. 'rebase -i'), there's also the shortcut of passing the '--squash' option to the final 'merge' command. This, unlike the standard 'merge' does not create a commit but instead applies all the commits from the merged branch into your working tree. You can then review the changes and create the commit yourself.
- jamesrom 13y agoI still don't understand why everyone has this misguided quest for a clean history. An accurate history is much more important. Rebasing destroys historical information. I can't really see any advantages of rebasing when a merge does the same thing but leaves two things rebasing does not: 1) a point to rollback to if things don't work out, and 2) an explicit entry of when your branch was brought up to date with master.
- a3n 13y agoBecause no one cares about an individual's doodles and false starts on a feature branch, or an exploratory branch off a feature branch, they only care about the final difference between before and after merge. Explorations are an unnecessary distraction.
- sanderjd 13y agoI disagree that categorically "no one cares": https://news.ycombinator.com/item?id=6457243 https://news.ycombinator.com/item?id=6457243
- a3n 13y agoI think phrases like "no one" should be understood as no one modulo a small number of exceptions that does not noticeably affect the majority trend. Always.
- Ygg2 13y agoBecause clean history is easier to bisect. It's easier to visually track problems, (aha so you changed thing A in branch br12 and thing B in branch br13 as opposed to wait so person A branched into br12, then person C branched into br23, then it got merged with br74, which was merged with person D on branch br84..). Less entagled workflow is easier to untangle and consequently understand even if it hides some stuff. Also it's visual clutter. If your history looks like train map, your project is probably a train wreck.
- 13y ago
- barrkel 13y agoIf you work with other people, this model doesn't work so well, IME. In particular, rebasing is very hazard-prone if someone else may have checked out your branch. If you're working on a feature that needs changes in multiple components and is broken without coordination, you may be working off the same branch, or have separate branches with inter-merges. Either way, rebasing will cause trouble.
- untothebreach 13y agoThis model works well for my team of around ~4 people. Not sure how it would scale to larger teams, though.
- barrkel 13y agoIt depends on the complexity of the app as well, and how much vertical integration there is, and what kind of development pressures there are (in a startup, the deadlines can be very short).
- viraptor 13y agoIt works well if you keep changes small. Basically if you're making a change that integrates with some other place that someone else needs to update, that looks like two separate changes to me. Of course you can do big feature branches that change a lot of things at the same time, but you're right - that won't work here. Regarding big projects -> gerrit works pretty much the same way (but also forces you to squash changes into a single commit). This is used successfully by cyanogen and openstack people at least. Those are fairly big teams.
- reledi 13y ago> gerrit works pretty much the same way (but also forces you to squash changes into a single commit) That may explain why one of the committers I work with on an open source project heavily suggests squashing changes into a single commit when merging topic branches into master. He works with gerrit at his day job! Personally, I think it's better to only squash experimental commits or minor stuff like removing a newline, and to keep development of a feature spread out over several commits if it makes sense. Makes it easier to revert back to a specific commit.
- allr 13y agoWe use the exact same model but we have a dev branch for our staging server, thanks for writing it down!
- tlo 13y agoWhat if you pushed your feature branch and then need to fix something in that branch later? How do you handle this case as you shouldn't rebase a pushed branch?
- reledi 13y agoIt's fine to force push to a remote branch if it's a personal branch, that is, no one else is working on it but you. (Or it's fine if you've previously discussed with your team the implications of force pushing to shared branches, and they're okay with that because you all know what you're doing.)
- koobe 13y agoThis feels like the working with SVN/P4 again. Main difference here is having your work in progress visible to others in a feature branch. Also rebase -i being less of a pain than svn update.
- caioariede 13y agoI never use rebase, but I don't see problems if your branch is local. I would prevent rebasing after pushing the branch to remote. Anyway this branching model doesn't looks so that simple.
- calinet6 13y agoThis is exactly how you do git. Sanity. Thank you.
- coherentpony 13y agoMaybe it's just one point of view, rather than a clear-cut, 'this is how you do git.' For example, my point of view is that master should never contain development work. master should always be stable. In this case, the post here does not jive with that point of view.
- shawnps 13y agoWe used a very similar model to this at my last job, and I'm struggling to get my current team on board with this type of process. I think the main problem is that people don't trust continuously deploying master because there aren't enough tests. In my ideal world, every commit is tested (with Jenkins, Travis, Buildbot, etc), and then if the PR includes tests for the code and the build passes, the reviewer says LGTM and the committer presses the merge button on GitHub. Once the button is pushed, a build of master is triggered. If the build passes, the code is automatically deployed.
- wpietri 13y agoMy world really changed once I started working with code bases that had excellent test coverage from the get-go. At my last shop we combined that with pair programming, feature switches, and a few other tricks, and we basically never branched. You'd pull, work for a few hours, push, and 10 minutes later your code would be live. It was in one sense freeing: the release overhead of other shops was gone. And in another, it inspired more discipline. Knowing that everything you were writing would shortly be live kept you on your toes. You could never leave something for later; there was no later. I loved it.
- shawnps 13y agoThat sounds really awesome! I'm guessing I'll just have to sit down one day and write a whole bunch of tests, and then hope that everyone else will see the benefit. So you mean everyone just pushed directly to the upstream master?
- wpietri 13y agoIf I understand your question rightly, yes. Looking at the Github history, we did actually have 6 branches over the life of the project. All were extended technical experiments of one sort or another like trying out a new templating approach. 2/6 were merged. But all normal coding was pushed to master with no branching (beyond a local checkout and local commits, which are a sort of branching, but none of those lasted longer than a day). There, any checkin triggered tests, and any build that passed the test was pushed live. If you want others to see the benefit, I'd encourage you to pick a specific area of the code, test the hell out of it, and make sure that a) tests are easy and quick to run on dev boxes, and b) every checkin is automatically tested. I'd start small, and one good place is a chunk of important business logic. It's even better if you use the tests to support refactoring and general cleanup of an area people know is messy. If you do this right, then people will have two experiences coding on the project. In the tested code, it's pleasant and safe. In the messy code, it feels dangerous and scary. Over time they may get it. Note that this is really hard to get off the ground in an established company and in an existing code base. So if they don't catch on, don't feel like it's you. (I generally cheat by being the first person on greenfield projects, so the first line of code written is a line of test code.) Also, if you get stuck while trying to clean up legacy code to make it testable, Michael Feathers' book "Working Effectively with Legacy Code" is very helpful. Good luck, and feel free to drop me an email if you end up with more questions.
- Frostbeard 13y agoIn my team we do something superficially similar, but instead of rebasing we just merge changes from master into our feature branches whenever master is updated. This seems to result in fewer conflicts for us, despite what you might expect. Also, when the feature branch is to be merged into master we do a squashed commit so that all changes from that branch show up as one commit in the main project history. The feature branch's commit history is preserved in the repository (thought not in the master branch), so it's not really any more difficult to roll back partial changes. Our situation is likely different from many projects though, as we only ever have one developer working in a given feature branch.
- reledi 13y ago> The feature branch's commit history is preserved in the repository (thought not in the master branch) This would require you not to get rid of the branches (remotely and locally), right? GitHub does allow you to undo the deletion of a branch, but is that only for a certain time period? I like to delete my branches as soon as they've been merged in.
- Frostbeard 13y agoWe leave the feature branch on the remote repo indefinitely, but we really don't need to do so. The diff between the feature branch's squashed commit and the previous commit of the project usually tells us everything we need to know when a problem crops up. We keep the feature branches "just in case", but in practice they're never used once the branch has been merged into production.
- eknkc 13y agoIn a similar model, I just commit hotfixes on the master branch. What is the negative implication of this? If I had a branch for them, those would just be merged back immediately with one commit anyway.
- _prometheus 13y agoNo rule is sacred, and your mileage will vary. For me, having a pull-request for the hotfix helps us run continuous integration tests, code-review, and ensure relevant people get notified automatically of the fix.
- programminggeek 13y agoI avoid rebase like the plague if I'm working on a team, and if I'm not working on a team I don't see the need for it much either.
- djbender 13y agoRebase is good for when you need to rewrite or clean-up history. For example: all those "WIP" commits you'll frequently see aren't exactly helpful. If you want to rewrite history of a branch that others are actively working on, well then you're going to have A Bad Time™.
- jpiasetz 13y agoDo anyone know how that branch image was created? I've been wanting to do something similar.
- nvarsj 13y agoIf you're looking for an automated tool to do this, take a look at gerrit. I used it successfully at my last day job. It basically enforces this model. The quality of our commit history changed quite dramatically.
- rsanheim 13y agoInterestingly enough, most folks working on GitHub.com don't use this model. We actually use a simpler model, and usually merge to our feature branches rather than rebase. I'm not sure if Zach's latest talk(s) goes into this level of detail. I think a big part of the reasoning is because we tend to push up branches really early to open PR's and get discussion going. And of course rebasing public branches generally leads to hell. I know some other .com devs will rebase privately before pushing a large branch, but I would say 80% of work is just done with merging.
- wting 13y agoI think it depends on how public and how many contributors you have to a feature branch. I think author has the assumption that there is typically one dev per feature branch. Once a feature branch is being worked on by multiple devs (and hence multiple feature branches forked off), it is a public branch and should use a merge based workflow.[0] I personally use a rebase workflow on private branches before merging since it makes for a cleaner history. I've seen devs merge a branch with 100+ merge commits and it absolutely destroys git history. [0]: http://lwn.net/Articles/328438/ http://lwn.net/Articles/328438/
- purephase 13y agoThis is exact same workflow I use. If it's a feature branch that I'm working on locally, then rebase -i is my friend as I can squash commits. But, I rarely stay in a local branch for longer than a day or two for fear of losing work and no developer is an island. The second it is shared, it's merge only. Rebase conflicts always cause more grief than it's worth.
- funkaster 13y agoI agree with most of what is suggested here, except forking. I think that even for small teams forks are the way to go: you get a cleaner upstream, plus you get a backup of your local repo.
- dreamdu5t 13y agoYou can use tags to present a clean history of features added or releases, while still preserving the actual history of commits... Using rebase to clean-up (destroy) your history is an amateur solution to having a proper branching/tagging workflow.
- jessaustin 13y agoTruly, "rebase vs. every-commit-is-precious" is the "vi vs. emacs" moot question of our time. EDIT: haha, I just reminded myself of the "Every Sperm is Sacred" song from Meaning of Life.
- potomak 13y agoI suggest also reading "GitHub Flow"[1] by Scott Chacon about this topic. [1] http://scottchacon.com/2011/08/31/github-flow.html http://scottchacon.com/2011/08/31/github-flow.html