Skip to content

Comment on Minimum Viable Git for Trunk-Based Development

Comments

I finally understand why some people are so against rebase. They're doing it wrong.

I've always heard people talk about how it doesn't scale, but I use rebase like 99% of the time, and have worked on projects with hundreds of ICs. This is the first time I've seen someone explain it in a way where I get it. NO I'M NOT FORCE PUSHING TO MAIN YOU SILLY NILLY! Turns out I'm "squash rebasing." I guess I didn't know I need to specify that.

I do it slightly differently tough. I use git commit --amend to build up a single commit as I go.

    git checkout -b blah-feature

    # do some work

    git commit -m "Main description of my feature"

    # do more work

    # no -m, and then I just add bullet points for each subsequent change in vim (example below)
    git commit --amend

Then, once I'm ready to make a PR I do the following:
    # pulls from remote without merging
    git fetch origin main 

    # adds my single commit to the end of the current main
    git rebase main

    # push up feature branch for code review
    git push

    # get yelled at about --set-upstream, and copy/paste that command :-)

My commit messages typically look like:
    Add some new feature

    - do some sub task
    - do another sub task
    - ...

I don't agree that folks who rebase multi-commit branches are "doing it wrong". Even if there are multiple stops along the way, that should not be considered a bad thing if it's understood what it is doing.

The way I look at it, lets say I have 10 commits. If I rebase main, commits 3, 4, 7, 10 have "conflicts" with the code that is on main now compared to when I started writing my feature branch and making commits. But, now, I have an opportunity to update code in each of those commits as if I was writing it based on what is now currently on main. If done like that, incrementally, it usually doesn't cascade into conflicts on each commit.

The problem, IMO, comes when at commit 3, the dev says "Oh, I did this like this in commit 10, so let me just put that solution here in commit 3 to resolve this merge conflict". Now, instead of 4 conflicts, you have conflicts on all of the commits between 3 and 10 (because the dev in effect moved the fix from 10 up 7 commits from where it originally was committed). Instead, each conflict resolution should aim to maintain the code as close to the committed code as possible while integrating the code from main. That way also, the feature branch commits still reflect the iterative process that having multiple commits is designed to show.

I don't embrace a FULL squash rebase, but I do embrace cleaning up your branch commits with an interactive cleanup rebase (not on main, just going through the commits for the branch and squashing any minor fixes that belong with the previous commit, etc.) THEN, once you have a clean feature branch, rebase main. The feature branch may now have, instead of the 10 commits above, eliminated 6 commits that were just things like minor test fixes, typos, etc, and now only has 4 commits total. Instead of 4 conflicting commits, it may now only have 1 or 2, making the rebase simpler as well. And the branch still maintains the traceable history of the development of that feature (assuming good commit messages were used, which is not something the original poster values either).

Many times have I seen a green developer throw up their hands at a rebase attempt, after which we learn they were doing this:

    git checkout master; git pull

    git checkout -b fb

    git commit

    git commit

    # new changes arrive on master branch
    
    git checkout master; git pull; 

    git checkout fb; git merge master

    git commit

    # "went to the git brownbag and heard about rebase for the first time, 

    # missing that part up front about not intermingling merges with rebases 

    # and not having a good mental model of git

    git rebase master

    # WTF conflict everywhere! rebase sucks

The flow you have described works (besides the last ‘git rebase master’), though. When ‘git merge master’ is run, the developer either get conflicts (which can be then fixed) or not. After that ‘git push’ and you can open a PR. I certainly don’t see anything wrong with that flow.

Yah, I don't think anyone minds those kind of rebases. It's when they're done on shared branches like master that they're incredibly messy and dangerous.

That totally makes sense. I never really dug in. Mostly I'd tell people I always rebase in passing and get a glare or snarky comment, but never bothered to argue about it because it works for me and never caused issues.

I use git commit --amend to build up a single commit as I go.

While this is a sensible approach, it doesn't work in scenarios where you essentially have to "test in production" to actually test things (Jenkins, looking at you). I've experienced some of that in the real world, and combined with the inability to force-push, it seems like the squash rebasing is the most sensible thing to do to keep main clean within these constraints.

Slightly off topic

get yelled at about --set-upstream, and copy/paste that command :-)

But you might like this https://git-scm.com/docs/git-config#Documentation/git-config...

I just added an alias

  alias gpush='git push --set-upstream origin $( git branch --show-current )'

`git push -u origin HEAD` also works!

Why not just ‘git merge main’ instead of ‘git rebase main’?

Because they do different things. It's right there in his post:

# adds my single commit to the end of the current main

The biggest benefit to this IMO is that you can resolve conflicts in YOUR branch, get it all cleaned up, and then when you merge there are no conflicts. This allows you to test any changes made during conflict resolution in your feature branch still.

No, if you want to update your local branch first then the correct way to do that would be to run:

    $ git checkout feature-branch
    $ git merge main
    # test stuff, make sure everything looks good
    $ git checkout main
    $ git merge feature-branch --no-ff
No rebasing or other history rewrites required.
AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.