Hacker News new | ask | show | jobs
by no_wizard 1044 days ago
rebase and cherry picking are both cornerstones of trunk based development workflows, and those have proven to be extremely successful in my experience, vs other methods (like Git Flow, the GitHub overly simplistic branch per feature and merge approach, which feels like trunk based but isn't etc.)

rebase makes roll backs extremely easy if you need to roll back specific commits because of bugs and makes releases easier via cherry picking (so you don't slow down trunk merges just to do a release) and allow for fine grained continuous deployment that is harder to achieve than without it.

It is my experience however, that either everyone needs to rebase or you end up with issues eventually when only some developers are and other ones aren't.

I don't care as much for squashing myself as a general case, as you lose fine grained per commit rollback strategies though

2 comments

Blindly squashing every branch into one commit is lame and done by people who have either never had to bisect a bug or too lazy to figure out how to properly rebase. Where squashing is important is turning a work in progress branch into a series of commits for the master branch. There shouldn't be any commits fixing your own shit, for example. I don't want to see one commit where you do the work then five commits fixing your own work. Nobody needs to see that. It only makes things worse.
> It is my experience however, that either everyone needs to rebase or you end up with issues eventually when only some developers are and other ones aren't.

The only time I merge is when I'm working on a shared remote branch. I haven't found a workflow (although I'm all ears if you have any suggestions).

Here's my current workflow:

1. write some code on a local branch

2. upstream has new revisions? rebase my branch on top

3. if not finished with my task yet, go to 1

4. if ready for review, open PR

5. if accepted, squash and merge

6. if changes are requested, write more code

7. upstream got more commits causing a conflict? don't rebase! it will screw up the PR history on GitHub and can cause issues for reviewers who might've checked out your branch locally and maybe done some experiments. merge upstream into your local branch. then you can push fast-forwardable commits.

8. push new commits to PR and go to 5

I used to think of rebasing as just rewriting commit history. But now I also think of it as altering the history of collaboration that is captured in a PR. So I switched from rebasing onto new upstream base branch commits and force pushing to PRs that already had reviews, to merging in new upstream base branch changes. I only do this after someone else has done anything on my PR; if I open it but nobody has reviewed yet, I'll do the rebase/forcepush to keep it current until someone does.

I prefer squashing to merge because I prefer the default branch to have one commit per unit of collaborative work. The way different people split up commits on a branch is arbitrary and varies widely; you'll never get more than 2 engineers to agree on a convention here. Keep all the messy stuff in the PR, and you can always revert one of those individual commits if you want finer-grained rollback. If you want a PR to have generated more than one commit, then it should be more than one PR.

> I only do this after someone else has done anything on my PR; if I open it but nobody has reviewed yet, I'll do the rebase/forcepush to keep it current until someone does.

I believe the only reason to do so is GitHub's lackluster PR UI. Force-pushing with an updated version of a branch after a review works reasonably well with GitLab's MRs.

> I prefer squashing to merge because I prefer the default branch to have one commit per unit of collaborative work.

There's no reason to squash when you can create merge commits from fast-forwardable state instead (again, one of the easily achievable options in GitLab's UI; GitHub doesn't make it easy AFAIK). This way you don't lose commit granularity while you can still obtain the "one commit per unit of work" view with simple `git log --first-parent` (or do the opposite and skip the merge commits with `git log --no-merges`).

> Force-pushing with an updated version of a branch after a review works reasonably well with GitLab's MRs.

The problem I run into is that other people have different workflows.

If they `git checkout remote/branch`, then everything's fine. But if they want to make a local copy of the branch, it'll get all messed up if I force-push. And I only want to adopt practices that are as robust as possible in the face of the possible ways other people could work.

For me, individual feature branches feel private, even if they’ve been pushed to a hub repository for others to view and pull. I wouldn’t push to someone else’s branch and I frequently force push to my own branch without worrying what it will do to others repositories.

The only thing that is sacred is the main/master branch. Everything is else just a speculative idea that, until reviewed and applied to master, is ephemeral.

(I’ve tried collaborating on a branch before but at the end of the process it’s hard to review because you either feel like the other party is rubber stamping their own code alongside yours, or you need to find a third party reviewer which spoils the 1:1 nature of almost every other code review I do.)

> (I’ve tried collaborating on a branch before but at the end of the process it’s hard to review because you either feel like the other party is rubber stamping their own code alongside yours, or you need to find a third party reviewer which spoils the 1:1 nature of almost every other code review I do.)

In my experience, that's part of the negative side of pair programming as well, although I really like it in general.

> There's no reason to squash when you can create merge commits from fast-forwardable state instead

Sure there is. Less noise commits.

Did you mean to say "less value in commit graph"?

It's literally just a matter of a single command line argument to switch between views of whole MRs and individual commits, and both those views can be incredibly useful (especially during bisection).

I still haven’t tried your suggestion, but would it be able to show only merge commits from PRs already merged into main, while still showing all commits on my local work branches I have in progress?
What's an MR?
My workflow is almost identical to yours except step #2. Why rebase on main when you can just merge from main? It's much simpler, less likely to get hairy merge conflicts. If you're going to squash your PR anyway, the end result is identical.
I really don't get all these people who insist on usingrebase instead of merge. Who wants to spend time resolving meaningless conflicts?! Every time I try it, I instantly regret it.
> I really don't get all these people who insist on usingrebase instead of merge.

I prefer not to squash before committing. I like having smaller commits in my history.

And if you don't squash, then using merge to fix conflicts with main/master before merging looks a lot more confusing.

> Who wants to spend time resolving meaningless conflicts?! Every time I try it, I instantly regret it.

Typically it doesn't take a lot of time unless you do something weird. Although to be fair to you, it does take more time than using merge.

I like being able to see the graph with my commits lined up on top of the latest main revision. It helps me order my work in my head. There’s probably a bunch of other ways to visualize that, I just haven’t learned them yet.