Hacker News new | comments | show | ask | jobs | submit login
Simple git workflow is simple (atlassian.com)
219 points by durdn 1348 days ago | hide | past | web | 112 comments | favorite

The perennial problem with discussions of Git workflows is the underlying belief that there exists, if only we can find it, the One True Workflow. This belief is false.

Git is a powerful, general tool that lends itself to just about any workflow imaginable and, because of its adaptability, different teams will naturally converge on different Git workflows as "right." These teams, however, have a hard time imagining and thus accounting for the conditions and preferences of other teams, and end up advocating for their workflows as the best workflow.

Thus we end up with strongly held and yet contradictory beliefs. Some people claim that "rebasing is a bad habit: it destroys history" while others claim that "rebasing is a good habit: it prevents repo cruft." Who is right?

It depends on your preferences, which ought to reflect your team, your project, and your company culture.

For my projects, I prefer to edit my work into tight, clean commits before merging them into the mainline branch. That's because I value the logical story of my software's evolution and not the physical story. I want my commits to tell the story that Feature X was built from three sequentially self-supporting changes XA, XB, and XC, not that, while developing Feature X, (1) I was sick for two days, (2) Bob committed an important unrelated hotfix to the mainline tree that (3) I had to work around, and (4) Sally had to later revert Bob's commit. That I was sick, that Bob commited a hotfix, that I had to work around it, and that Sally rolled it back are all real. They happened. But none of those things are fundamental to the nature of Feature X and how I rendered that nature into code. I consider that stuff noise and make sure it's gone before my commits land in production.

But that's me. Maybe you care about that stuff. If so, your Git workflow and mine are going to be very different.

And that's okay.

Sure, but there are still workflows that are just plain bad[1], and articles like this one are an effective way of giving users better alternatives.

[1] Last summer I interned for a company that had recently switched to git. The workflow was: you are assigned a feature and begin developing it on the shared "development" branch. As you make commits you note the hashes on the company issue tracker. When the feature is finished and signed off, the DevOps people manually parse through all the comments on the issue, manually cherry-pick (!) every commit (that you remembered to write down) to the "production" branch, push, and hope they didn't miss any.

The point I'm hoping to make is that there is no universal < operator on workflows that lets us rank them in a way that makes sense for most teams. Different teams necessarily have their own, widely varying < operators, and applying these operators to the set of plausible workflows causes wildly varying workflows to rise to the top.

There are, however, workflows that are so bad that they rank poorly under your < operator, my < operator, and just about every other reasonable person's < operator. Your example makes this painfully clear.

Still, someone at the company you interned at had an < operator that pushed that horrible workflow to the top of the list. You can argue that that person was crazy, and maybe you would be right, but maybe that person wasn't. Maybe that person's < operator accounted for things you couldn't see. Maybe the company needed the Git workflow to contort itself into integrating with legacy processes that would have been hugely expensive to change. Whatever the reason, that person's < operator is not one that you or I would want to have forced upon us.

Why then should we assume our personal < operators good enough to force upon anybody else, let alone everybody else?

Not sure you were contesting the presented workflow in (1) (2) (3), but that won't happen when continuous rebasing on a branch. Bob and Sally's commits will remain on master and not be part of your branch at all; at merge time your feature will look like it was branched off the most recent master and contain only relevant commits.

I wasn't contesting the original article's workflow (which is rather like the one I use most often), but picking one of the hotly contested battlegrounds of the Git Workflow Wars – To Rebase or Not To Rebase – and using it as an example.

Here's why I care about that stuff:

I work at a place that has some code in production that's over ten years old, and which no one now working there wrote. We have many more discrete systems than developers. The repo history, including its comments (actually currently in SVN, where rebasing isn't a ready option), is a major tool for interpreting the intent of authors now gone (or who now don't remember writing it, something I'm guilty of, certainly). The clean narrative you are asking for is there, in tickets and internal wiki pages. The actual history of commits helps tell a different story, about whether it was intentional that line 493 was omitted because of the effect on another part of the code, or whether it being missing is a merge artifact or other tool screwup.

We're about to switch to git, and one of the things I worry about is that newer developers steeped in the ways of rebasing will come on board and "clean up" their commits to hide informative early missteps and paper over the cracks and seams of their work with single commit messages per feature which afford no understanding of the difficulties involved in developing it.

> The perennial problem with discussions of Git workflows is the underlying belief that there exists, if only we can find it, the One True Workflow. This belief is false.

Nothing in the post explicitly says this, nor is it implied. You just took 7 grafs to say "the best tool for the job".

Thanks for your comment.

To clarify, my comment was about "discussions of Git workflows." For example, the very discussion occurring here on HN in the wake of the original post. In this discussion, you will find numerous comments predicated on the implicit belief that there is some global ordering on Git workflows and, therefore, that one workflow can be strictly better than others. Some examples from the top level:

> I think http://nvie.com/posts/a-successful-git-branching-model/ is simpler and more robust. [1]

> Just use Gitflow peeps. It's simple, not mentally taxing, and having a feature branch for each feature (JIRA ticket, or whatever unit you're using) makes things very atomic and simple. [2]

> How is this in any way better or simpler than Git Flow? [3]

> Rebase is a bad habit to get into (because it means other people can't pull your branches), and a pain to fix when it conflicts. Merge master into your working branch instead. [4]

Also, I didn't write 7 grafs to say "the best tool for the job." I wrote 7 grafs to say that there is no "the job." Rather, there are many different jobs. Your job might be to record the physical story. Mine might be to record the logical story. Different jobs.


[1] https://news.ycombinator.com/item?id=7037265

[2] https://news.ycombinator.com/item?id=7037362

[3] https://news.ycombinator.com/item?id=7036934

[4] https://news.ycombinator.com/item?id=7037057

For me, more the number of splits a commit can be divided into, the better. Even for simple 2-line cleanup, I'd not do it with the current patch I'm doing. This irks my fellow programmers sometimes though, who just want to get the work done.

I've developed this habit as a consequence of using history to understand the context of a piece of code. Big commits make life harder for future maintainers.

> It depends on your preferences, which ought to reflect your team, your project, and your company culture.

Like all tools (especially software ones), it's not how hard you swing the hammer, but rather that the nail ultimately gets secured. The two are often misinterpreted against each other.

> When development is complete record an explicit merge

This is so important I felt it necessary to quote it and restate it as a comment.

Not knowing this ahead of time caused me to have a serious problem on ship day that most source control solutions make trivial to fix - it got solved in the end, but that hiccup was unwelcome. The result was that I threw git out as a viable option for source control (until hg screws me I have no reason to switch back beyond its popularity).

Bad defaults are bugs imo...

EDIT: to be clear i'm referring to the advice to use --no-ff for a merge. i am of the opinion that --no-ff should be the default, because using it causes no damage, but not using it can cause problems.

What are you talking about?

I believe he is referring to the git workflows and tutorials that encourage rewriting history in a potentially lossy way.

Mercurial can do the same sort of history rewriting, to a point, but it is not the default workflow and requires that you explicitly enable that functionality. Even then, when you push a modified history to the central repository, you have the old history around still. Whether or not this is desired is up to your team's workflow, but it does make it harder to lose something.

not exactly, i'm referring to the difficulty in undoing a committed merge if you don't use the --no-ff flag as suggested in this article.

i believe this is precisely why they suggest using it - because on private branches you can undo merges in much more destructive ways which are not viable on a shared repo - they suggest using --no-ff for when you merge in a feature branch

(edit: it is precisely why and there is an article linked from the original discussing the pros/cons of merge and rebase)

What on Earth does "unpick" mean and where does that term come from?

i'm using it in the sense of English - its not a specialist term or a piece of jargon. i.e. I mean 'undo', 'revert', 'reverse' - unpick just feels more appropriate because its often a fiddly process if you are doing anything more than a simple revert or back-out type operation.

Sounds like the opposite of cherry-pick.

i'll edit it since its confusing. in hindsight undo is the obvious choice of word

if you read the section with the header i quoted - that is the thing i am referring to. using --no-ff to make it easy to unpick a faulty merge on a shared repo.

I understand that collaborating on code is a hard problem. But if this is the simplest solution, part of me wants to throw it all in the trash and start over. It's just not good enough.

I read a funny quote somewhere, it basically said that git is a great library for building a DVCS...

Basicailly, I agree with you. What I'd personally like to see more of is an easy way for a company to define a workflow for version control, using git as the underlying mechanism, that fits exactly how they want it to work (think, if the company wants Git Flow, or some other workflow, they define it in my imaginary tool), but for the most part the developers never have to drop down to git to use it. They have an abstraction layer over the top of it.

I saw a paper, gitless, I think it was, that is trying to do something similar but less ambitious. Perhaps in the future we'll see stuff like it. GitHub Desktop and Atlassian Stash also do something similar, but not quite what I'm getting at.

This is a fantastic idea. Even the "nice" git tools like Github's desktop app don't abstract over tracked files and branches and all the confusing git plumbing. It'd be so much better to just be able to click "I'm working on a new feature" and "I'm done with the new feature."

I believe that version control should really get out of your way, and right now, that definitely isn't the case. To me, all the arguments about git's power just sound like "why use Dropbox when you can just sync your files with FTP?"

> It'd be so much better to just be able to click "I'm working on a new feature" and "I'm done with the new feature."

Maybe, but it might instead be better to ask people to invest a small amount of time in learning to use tools that make them more effective at doing their job. "I'm working on a new feature" and "I'm done with the new feature" are, sadly, not actually expressive enough concepts to deal with the problem.

Syncing files with FTP is pretty much at the same conceptual level as "Use Dropbox". Git solves problems significantly more complicated than "I'm working on a new feature / I'm done working on a new feature".

EDIT: when I say "conceptual level", I mean, "what you do with it", not "how easy it is to use". Obviously, Dropbox is more usable than FTP. My claim is that Git provides a much different level of power than "I'm working on a feature/I'm done with a feature", which is not a sufficiently expressive concept to deal with software development.

> Syncing files with FTP is pretty much at the same conceptual level as "Use Dropbox".

I disagree. My mom loves Dropbox -- she just sticks a file in a folder like she always does and it's magically synced. If she were to use FTP, she'd have to set up a server, remember login credentials or find her public key, and grab an FTP client. And not every client supports automatic syncing either, so she might have to manually trigger a sync.

Of course, FTP has way more power and flexibility than Dropbox, just like git vs <proposed VCS>. If your workflow is especially complicated, I'm sure all the git functionality comes in handy and an abstraction would be a hindrance. But most workflows, I'd argue, don't need all the plumbing.

If you use something like SourceTree, it has buttons for exactly those things, after you hit the 'Git Flow' button in the toolbar.

So as long as you want to use the Git Flow model, which is probably the most widely understood/used, you wish has already been granted!

That's the app was trying think of! Cheers :) what I want to see, is a way of building those work flows in sourcetree, and pushing that out to developers. Would be awesome... And I think I might try and hack on it perhaps.

Which part do you dislike? I think the basic idea of (1) Create a new branch (2) Develop your feature and commit (3) merge your changes back to master, those steps are as simple as it can possibly be. So is it that this article recommends rebasing (something you don't need to do) what makes it seem non-simple? Or is it the commands themselves (git doesn't have a great ui)?

For a start, lines like:

"At this point solve any conflicts that come out of the rebase"

Hide (in my experience) huge amounts of complication -- this can get very hairy, and it isn't discussed at all how you do it (and it's more complex than any of the rest of the stuff shown here).

perhaps because it's not in any way different than "At this point solve any conflicts that come out of the merge"? isn't conflict resolution usually done on a case-by-case basis?

So if you e.g. want to abandon the conflict-fixing, and do some things on your branch to make merging easier first, you've got to use a special command, and it's different depending on whether you were merging or rebasing (which is still a great improvement over a year or so ago, when you had to do an incantation like git reset --hard HEAD^). Contrast with svn where abandoning a merge is just a "svn revert" like any other.

What is so special about "git merge --abort" and "git rebase --abort"?

Special as in they exist solely for this purpose.

Agree 100%. Whenever go beyond the very basic functionality in git I have to think so hard about what I'm doing that I lose flow on my actual development. In most cases I find using git to be more daunting than actually writing code.

Maybe I just don't use it enough. Right now I'm in a job where my git workflow is: pull, (do some work), commit, push.

> 4. To keep your feature branch fresh and up to date with the latest changes in master, use rebase

Could somebody please explain this more? My understanding of rebase which comes from [1] is that it's used to bring a feature branch onto a master branch, or similar, and 'erase evidence' of there ever having been a branch, and squash the intermediate commits on that branch, to make things cleaner.

For bringing changes on the master branch into your feature branch, what's the benefit of using rebase instead of just normally merging the changes in? I'm clearly missing something here. They say 'Resolving conflicts during the rebase allows you to have always clean merges at the end of the feature development.', but I don't see what merge vs rebase has to do with resolving conflicts -- you have to resolve conflicts when you merge master into your feature branch just the same.

I can understand using rebasing to keep the master branch's history 'clean', but what's the reason with a feature branch?

[1] http://git-scm.com/book/en/Git-Branching-Rebasing

Rebasing will first undo your changes, get the latest changes from the target branch, then slap all of your changes at the HEAD. It makes things a lot cleaner and easier to revert (without digging through the reflog), whereas merging will intertwine your changes with the master branch.

I use it to keep things organized, and also (as you mentioned) for squashing consecutive commits.

TLDR: avoid millions of Merge branch master into xxx commits on a busy project, keeping commit history clean, and allow reverting merged branches easily.

OK. Re-reading the article for like the fifth time, I finally realize where I'd gone wrong -- the fact that rebasing from branch to master, and rebasing from master to branch, are pretty different things, used in different ways.

In case this helps anybody else:

I had always understood rebase as a mechanism that replaces merging a feature branch onto master, that allows you to squash all the 'messy' development commits on the feature branch, onto a single nice clean commit on master. In this model, you can be as messy as you want on the feature branch (with 'whoops bugfix' commmits and lots of merging in), and the feature branch is generally short-lived -- once you rebase+squash it onto master, the feature branch gets deleted, and you start a new one if necessary for further work.

The proposed model is the opposite -- you try to keep a clean feature branch. Every time you want to fold in changes from master, you do it as rebase, which has nothing to do with squashing anything -- it's about bringing forward the starting point of your feature branch to match master's current state. Then, when it's time to bring feature into master, you merge, not rebase, so the branch history is preserved, it's just nice and clean. And I suppose you can keep the feature branch around for more work on it, so it's almost more of a long-lived 'topic' branch with a bunch of individual features stringing along it.

The funny thing is, I've never seen a blog post that talks about both kinds of rebasing at once. Every one I've seen seems to look at it from one viewpoint or the other, which it possibly why rebasing can get so confusing (maybe I've missed one that does explain it well, both ways). The "git-scm" site describes the first way, but this blog post helped me understand this other way of rebasing:



I hope this doesn't confuse you, but I do feel compelled to add.. In both examples you mentioned, you merge onto master. You would break your teammates repos if you rebased a topic/feature branch onto master.

You ARE right, that before such a merge, it's a common practice to squash your commits on the feature branch to clean it up and then merge a single commit over to master. (To squash you use git rebase -i but you're squashing not rebasing).

If you were to actually rebase this branch into Master instead of merging it, it would change the commit hashes for commits already in master, leading to awful merge conflicts the next time a teammate tried to pull down your changes.

I wanted to mention this to hopefully connect the last few dots. The reason most articles don't talk about "both" these ways, is because really there is only one way, with a few different choices.

Maintaining a branch: If you need to bring changes from Master into a long-running branch, you can either do so with merge or rebase. Rebase is cleaner IMO.

Preparing to integrate your work into master: You can either squash some or all of your commits, or you can keep the history as-is.

Integrating into master: You always do this with a merge.

That's a good point, thanks for clarifying. In case anyone else is still reading, it's (ideally) a fast-forward merge. Fig 3-30 shows this:


So I guess I'm starting to see how these are somewhat the same thing in the end, just from different perspectives. Thanks again.

>I had always understood rebase as a mechanism that replaces merging a feature branch onto master, that allows you to squash all the 'messy' development commits on the feature branch, onto a single nice clean commit on master.

For squashing into a single commit, you can even use

    git merge branch_name --squash
But, yeah, rebasing is a nice and more general way to do it.

In this case, we want to have a logical history that says: this branch has these features A, B, C, D, and rebasing means that we can have the feature branch just have these commits, instead of "A, and then merge in some changes someone else happened to do, then B, C, then some other merges, then D."

I think http://nvie.com/posts/a-successful-git-branching-model/ is simpler and more robust.

To my mind git-flow is overcomplicated; I prefer http://scottchacon.com/2011/08/31/github-flow.html

I like that. It seems that git-flow is a good match for weekly/monthly releases and github-flow is a good match for daily/multiple times a day releases.

As far as I can tell the only real difference is the existence of a develop branch in git-flow that allows integration testing before a batch release.

I think these hosting providers are trying to get people into the habit of doing pull requests, which is something base git and git flow doesn't cover. A lot of small teams seem to rely on blind merges with, but as you grow you need better ways to comment/approve/deny changes that random team members might throw into a codebase.

Pull requests are built into Git. (Just a piece of trivia for you).

Yes, git-flow is excellent, but like any branch / commit scheme takes dicipline to follow. I often find myself (on personal projects) fiddling with bits on the 'wrong' branch, as I tend to jump ad-hoc from place to place in the code. Probably itself a discipline problem. :-)

I have a similar problem; this is what I do: I keep a dev branch to merge to/from whenever I switch focus.

For example, when I'm on branch Feat-A, but I want to make a change related to Feat-B (or I already have but haven't committed), I'll stash my changes, merge Feat-A into dev, merge dev into Feat-B, pop my changes off the stash, and commit.

The whole switch goes:

- "Oops, these changes don't go on this branch"

- git stash

- git checkout dev

- git merge Feat-A

- git checkout Feat-B

- git merge dev

- git stash pop

It takes half a minute, but it keeps my branches clean, and lets me move from feature to feature at will. I may add a 'git oops' alias just for this process.

Thank you - I've been meaning to think that process through. I'll be doing this from now on if I'm in the same situation rather than 'ah feck it, commit it'!

yepyep, this is also how i roll; stashing and popping!

Thanks for this -- looks very nice. Now, has anyone any experience with hg-flow (a mercurial extension that helps following a git-flow like model with mercurial)?


feature branches are awesome. My problem is usually in early protoyping, where I want to push my stuff somewhere, but often switch paradigms.

I.e. I just started learning Rails, building a new app from scratch, and you can imagine it becoming messsy. Before I get confident in a certain architecture, I would just push to master all the time with "some more blah" messages.

I think rebasing can be valuable in this sense, since it will destroy crappy history. I'm more found of the git flow workflow in a team development effort, expecially if your thingy is already in a production pipeline. I've found rebasing to be often very confusing and destructive, while merges are clear and easy to manage.

One reason I like git-flow is its insistence on two main branches, master and deploy. In a CI environment, it's great to have a CI pointing at develop so that "finished" features and merges are constantly being tested, plus, you always have a master branch which (theoretically) is only getting fed from fully-tested release branches. Master stays pristine. Develop should also be pristine but if it fails, it's no big deal.

Nevertheless, IME finding the right branching/release paradigm in group development situations has not been the biggest problem. The bigger hurdle has been reaching basic understanding of git and SCM tools in general -- even among groups of very good/experienced programmers.

How is this in any way better or simpler than Git Flow? IMO Git Flow is conceptually easy to understand and easy to implement. Using it on a pretty decent sized team (40+ developers) and it works great for us - and is easy for newcomers to the project to pick up.

This essentially IS git flow.

Edit: Never mind, I wasn't remembering git flow correctly.

This is most definitely not git flow. Git flow advocates explicit merges pretty much everywhere with no fast-forwards and definitely no rebasing.

Rebasing locally before "publishing" (pushing) changes to the central repo is definitely okay. It should always be done before pushing the branch for the first time, really, because if someone else has modified develop since you started your branch, you want to make sure your changes are still working and won't break the build (on develop).

You're right, it's not. I need to stop commenting on HN before I've had coffee. :/

Is there a link where I can read up the type of Git flow that you are talking about?

I, for one, like this workflow which is simple and elicits collaboration and creates history: http://scottchacon.com/2011/08/31/github-flow.html

"In the (somewhat less common) case where other people are also working on the same shared remote feature branch, also rebase changes coming from it"

I don't think this use case is uncommon, and unfortunately when you are multiple persons working on a shared remote feature branch you can't rebase the branch from master and then push it either.

What work flow do people who have shared remote branches use? Or do you think that way of working is broken?

This is definitely not simple. So much rebasing. Ugh.

> 6. Perform a final rebase cleanup after the pull request has been approved

I understood everything except this step. Could someone clarify this for me? Especially this part: "In some cases ... you can rebase also during development, but I strongly advise against it." Isn't the entire article about rebasing during development? Why did this become a "in some cases" thing now in step 6, when step 4 (rebasing during development) seems like the critical step in the whole process?

Otherwise, this is a great step-by-step (especially seeing the commands that get run for each step -- up until now I only understood the rebase process conceptually, but was always scared to try it due to not knowing the exact commands to run in the exact order, or which branch to run them on). Thanks!

[Edit: removed confusing paragraph.]

"Rebase also during development", I'm assuming they actually mean "squash" commits, since step 4 was all about rebasing. But if the whole point of rebasing instead of merging is to keep the feature branch clean as you go along, why wouldn't squashing "less tidy" commits also be strongly encouraged?

Man, you think you know git well enough, you've got git-flow down, then you read an article like this, and realize there are people who use it in a totally different way, and you're confused all over again.

I think he is talking about a cleanup rebase, where you squash all the commits you made where you fixed a typo in your docstrings or fixed your lowerCamelCased acronym keyword.

That's how I interpreted it too. Although personally I think all that should be done in the development stage. I prefer to only approve pull requests once they're ready to be merged. It helps avoid the possibility that some of your "cleanup" accidentally introduced changes in behaviour. Also, a clean pull request is easier to review.

I use a similar workflow and documented it: http://freeseer.github.io/contribute/basics.html#basic-workf...

One difference is that instead of fetching and rebasing changes from origin straight into your topic branch, we recommend checking out master, pulling in changes, checking out your topic branch and rebasing against master. This way master is also up to date.

As for the .gitconfig tip near the end, I don't think changing the behaviour of such a common command like pull is a good idea. Better to be explicit.

This is exactly how I do my git stuff. The only thing that I don't like about this is that you need to force your push after you rebash with master as you have noted. Also what solution do you use when you are sharing your feature branch with other people (especially with 1-2 other programmers) while still rebasing off master?

> Also what solution do you use when you are sharing your feature branch with other people (especially with 1-2 other programmers) while still rebasing off master?

We don't have that problem because we keep topic branches personal (but still public so they can be reviewed). In other words, our topic branches branch off from master, we don't branch off of someone's topic branch to build a new feature on top of it while the current feature is still ongoing.

We try to make branches short-lived and break larger tasks into small parts that can ship individually.

Just use Gitflow peeps. It's simple, not mentally taxing, and having a feature branch for each feature (JIRA ticket, or whatever unit you're using) makes things very atomic and simple.

This is simple and gives you one branch per feature. Gitflow doesnt offer any guidance on keeping a feature branch up-to-date, assuming either they are very short-lived (frequently untrue) or that you merge from develop polluting your history. In fact you can use this rebasing workflow within gitflow, both are good advice.

And also, if new people join your team, they've probably at least heard of it. There is benefit to being in the middle of the pack.

Rebase is a bad habit to get into (because it means other people can't pull your branches), and a pain to fix when it conflicts. Merge master into your working branch instead.

That's an unfortunate generalization. You can rebase all you want as long as you didn't make your private branch public. (and even then some communication with the other people makes it pullable: tell them to first git reset --hard xxxxx)

We use this more othen then not here, and never have problems. It's a great way to work on a dedicated feature while still getting features from others, yet doesn't suffer from sometimes hard to read history. Does this mean rebase is king and merge isn't? No. Is it the other way around then? Also no. Both are fine if you know how to use them.

> You can rebase all you want as long as you didn't make your private branch public.

True, but the big benefit of git comes from those branches being public, IMO.

> and even then some communication with the other people makes it pullable: tell them to first git reset --hard xxxxx

If other people are actually using the changes on your branch (and if not, why did they pull it?), you end up having to do staircase rebases, with everyone fixing the same conflicts again every time they rebase. It's not the end of the world, but it's noticeably worse than using merge.

> yet doesn't suffer from sometimes hard to read history

IME the only difficulty comes with tools that try and display a linear view of history, and with rebase you sacrifice an accurate time-ordering of commits, making it very hard to find a commit if you were working on several branches at the same time. As long as you configure your tool to show a tree/graph of commits, merged history is easy to follow, and keeps the time-order correct.

To me, the big benefit of Git is private branches. When I'm in development I don't need to build clean, atomic commits or have anything worth pulling. I write commit messages like "savepoint 2013-12-12 do not push". I don't want to think about version control because everything is still dirty.

I don't know if you've looked at the graph of a Git repo where people merge instead of rebase, but even in that view it's nearly impossible to track even the history of master. It's a mess. Rebase builds such cleaner graphs that I would only advocate merge when you have no reason to ever look at the graph view.

For me, almost all of the time, when I'm ready to merge to master I can almost always squash all my work into one or two clean commits. At that point a fastforward is the simplest solution. Merge-only workflows are great for long-lived public branches (if you have an integration and release branch for instance) but they're insane for feature branches.

> I don't know if you've looked at the graph of a Git repo where people merge instead of rebase

We use merge instead of rebase. Here's a snapshot of the graph:

  | | | | | | | | | | | | | | |                  
  * | | | | | | | | | | | | | |
  |\ \ \ \ \ \ \ \ \ \ \ \ \ \ \
  | |_|/ / / / / / / / / / / / /
  |/| | | | | | | | | | | | | |
  | | | | | | | | | | | | | | |
There are only 4 people working on the repo.

I'd expect 5 lines (trunk + 4 branches). What're the others?

Exactly! I feel like I need a drink after looking at that.

I think private branches are just branches not pushed to remote. Isn't the problem here now that you have a critical point of failure and at risk of losing everything if you're not pushing things to remote nightly. I always advocate regardless of pushing branches to remote and getting things off of your local drives if possible.

If you're not regularly backing up the machine you work with, you're screwed. Git is not necessarily the best tool for this, but when you have nothing better, it often works to set up a "backup" remote that other people can't touch and then just do force pushes.

well most our stuff is in "the cloud" so really if we wiped everything, it be just a matter of pulling backups and go. Setting up a backup remote for something so simple of merge vs rebase sounds off to me.

So it sounds like you don't have to push your code since your workstation is already being backed up then? We agree that you don't need to push your feature branches in that situation? I'm not sure, I feel like you just pulled some weird conversational jiu-jitsu where all of a sudden you're making my point back to me.

no our things like documents, database backups, emails, and source code all exist in the cloud. By suggesting my employees all push to remote daily, theres no risk of ever losing anything. All it takes one stolen laptop, one hardware failure to push you back xxx days, from your private branch. I don't know how long you work on a private branch but I have seen people wait close to two weeks during a 2 week sprint.

The Git system we use at my workplace has a private "backup" remote for each employee and a public "share" remote for each employee. So there's no problem rebasing all the time even if you push to the backup remote because it's not shared. Ultimately backups should be a totally separate concern from version control workflow anyway, even if you use Git remotes to back up your work.

I don't get why people hate merges so much; it records the history of what actually happened, which seems like a nice default. I find it can be helpful for tracking regressions, even on private branches that never get pushed.

me too. the only reason i can see is laziness when looking at history because merges clutter it, but even then the fix should be in some front-end tool and not git itself.

as a real world example bitbucket added a cool feature recently where they grey out merge commits.

personally i love rich and complete history, including merge commits - any practice that damages that is something i'll be highly reticent about adopting.

irl i generally don't need to time travel to achieve my goals...

"as a real world example bitbucket added a cool feature recently where they grey out merge commits"

Interesting. I went a different route by making it very easy for users to dissect a merge commit. For example, if you click on the "Find included commits" link in the first commit at:


you'll be able to see all the commits that it included.

The problem isn't history. The problem is meaningless history. If I'm working on file X and meanwhile file Y changes on the remote repository and those have nothing to do with each other you shouldn't need to do a merge. Merges should reflect situations where related changes happen concurrently. Otherwise it's just clutter and you can no longer separate the "true" merges from the noise.

Rebasing public branches is no big deal as long as it's a personal branch. This should be obvious to the others you're working with, if not, your team probably needs to communicate more.

The only reason I can think of for others to pull your personal topic branches are to review it locally or help you debug something. Others shouldn't be branching off of your personal topic branches to work on them, use feature flags instead.

Feature flags make it much harder to encode appropriate constraints into your type system, and make testing much less effective. It's very useful to be able to collaborate at a finer granularity than only sharing changes that compile.

It depends on the use case. The author specifically says it is a workflow for /continuous delivery/.

We do continuous delivery and our branches typically live for about an hour before they are pushed to production.

Continuous delivery is about working in small deployable steps and using techniques that allow you to release incomplete features into a production environment (Feature toggles, Branch by Abstraction).

Feature branches are pretty much the opposite of continuous integration. By definition your changes are not integrated into production or with other people using other branches


Feature branches really have nothing to do with CI per se. A feature branch is to test major changes without upsetting the stability of your build. Depending on your code review process, it also gives people a chance to give feedback and make changes before everything's merged back into develop.

In fact, the TeamCity CI system now supports automatically building feature branches -- so the two concepts are definitely not at odds.

>A manual on workflows does not come pre-installed with git, but maybe it should seeing how many people have questions on the topic.

    git help workflows

If it works for you then great, but it's kind of crazy to me that anyone would call this "simple". That strikes me as disingenuous, to say the least.

My biggest workflow problem is remembering to commit. Then it occurs to me to commit, I do a "git status" and holy crud, what do all those changes do?

So I'm resolving now to commit... when?

Any time a new test succeeds (without breaking old tests)


Any time I run a test


Something else I haven't thought of?

It needs to be something more concrete than "when you've done something significant". The mental energy drain of deciding "significant" is a killer.


I think the growing consensus on using a dvcs is that you should work on easily separated chunks of functionality in their own branch. Commit whenever you feel like it throughout the lifecycle of working on that feature, then go back and squash all those random commits into a few easy to understand chunks, and then merge that back into master.

For example, I'm working on a simple landing page and form. Some logical points for doing a commit may be something like:

1 basic responsive layout complete for mobile 2 progress on desktop responsive layout (going home) 3 completed desktop responsive layout 4 wired up forms 5 added validation to forms 6 cleaned up duplicate css 7 adjusted css for other, crappy, browsers 8 bug fixes 9 fixed a typo 10 bug fixes & final layout issues

Now I'm done and I want to merge that to master. But what I want the commit history to look like is a group of logical steps, excluding things that will be meaningless/useless to other people when they look back at the project history. So I would squash 2 and 3, 4 and 5, and probably 6 thru 10 so that I ended up with 4 total commits 1, 2/3, 4/5, 6/7/8/9/10 that get put onto master.

So, you definitely want to try to remember to commit over the course of a feature, but the actual times you commit are a little bit less important because you should clean up your history before you move it to master. In general I try to commit discrete pieces of functionality (like a working form, or a working layout, or a tested class/method).

As often as possible.

Then rebase it to a consistent history with consecutive small changes later when it works. The reason many commits are good to have is that it tends to be easier to extract small independent changes that way.

This is exactly the workflow I have been using for a couple of years now. I'm not sure that labeling it "simple" is accurate, but it is generally easier to understand than some other workflows I've seen.

In the (somewhat less common) case where other people are also working on the same shared remote feature branch, also rebase changes coming from it:

git rebase origin/PRJ-123-awesome-feature

At this point solve any conflicts that come out of the rebase.


I don't know about this, we've used this before and what winds up happening is a lot of

    git push --force
since the the remote feature branch's history is always being rewritten and won't match the local histories. We only rebase if the feature branch is being worked on by a single developer. And a bunch of other grief ... or am I missing something?


You can only really rebase onto one remote branch. If two people are working on feature branch PRJ-123-awesome-feature, then you both rebase onto origin/PRJ-123-awesome-feature. You have to merge with master if you wish to keep in sync.

Prior to one of you pushing to master you can opt to do a final rebase onto master, but I've always kept these long-running branches in history. I too try to avoid cluttering history with too many merge commits, but it's a very different thing if these long-running feature branches wind up as merges in history.

Interestingly enough, I was just documenting my team's workflow in my blog...


Very similar to this, but we add a couple of steps to allow a business owner to examine a feature before it gets accepted and also we use an integration branch to deal with merge conflicts before creating a releasable master branch.

The main problem I have with this workflow is step 6, after a pull request has been approved:

> (At this point if you have rewritten the history of a published branch and provided that no one else will commit to it or use it, you might need to push your changes using the –force flag).

I don't think it's a great idea to institutionalize what most would agree is a Bad Git Practice, especially in a multi-user environment.

The blog is down at the moment (returning http 503).

Here is the cached version: http://webcache.googleusercontent.com/search?q=cache:https:/...

Maybe a stupid question, but I am not clear on what happens if, in between you send a pull request and the code is merged with master, the master branch itself gets modified. In that case you couldn't rebase and you could have merge conflicts with master, or am I missing something?

git actually does come with a manpage on workflows: https://www.kernel.org/pub/software/scm/git/docs/gitworkflow...

Typical. They can't even keep their own website up. I had to use some of there tools in a job I had once and they were not reliable at all.

I really love the design and color scheme of the Atlassian website.

this post could have been titled "git workflow replicating workflow in centralized VCS (like CVS, Perforce, etc..)"

Applications are open for YC Winter 2018

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact