1. (major): it lets me commit at my pace, and then publish my work at the pace the team prefers (which is a combination of what the team wants and what won't choke the CI, but that's a story for another time). The ratio of my local commits to commits sent to code review is often 5-10:1.
2. (minor): because I hate to see a Git history that's over 50% made of "Merged X, Y into develop". It's pure noise. I guess there's probably a command line flag to filter them out, though.
Don't rebase shared branches.
It's amazingly powerful at making clear annotated changes. And removing small fixup commits for work in progress.
When someone says "never do x" there's probably a missing understanding of nuance.
No one maintains change logs in their repos most times, so a linear git history where you rebase existing branches on top of their base branches allows for a clean commit history on new features to be merged in which can then be squashed down for a linear commit history on the trunk branches.
Then you can use things like bisect, and just... ya know, read through your change log when you need to.
Shoot, you can even add a few details in the notes while you're at it. How about a link to the ticket and PR at the very least with some notes on implementation.
That's my approach, it really doesn't take much time.
But hey, if civil engineers had the level of rigor software engineers do we'd all be dead.
So you live with what you've got, do what you can on your own branches, and just accept that no one cares about having a clean git history cause we can't be bothered as a profession to spend a couple hours learning how one of the most important tools we use every day works.
I really discourage the squashing upon merge approach entirely though, because that's just a bandaid for lazy and/or misinformed developers to cover up the fact that their whole git workflow is completely borked.
Just don't: https://news.ycombinator.com/item?id=33518496
The lesson I learned was: Prescribe everything about the workflow because nobody is going to learn git. They'll skim your baby's-first-commit page on the internal wiki, but you better put everything important above the "push" section of the tutorial because that's where they'll stop reading.
All the nice flexibility of git just becomes risk. By the time you have enough structure in place that your team isn't shitting up the repo left and right, you might as well be back where you started: source control you hate, with zero flexibility, and you're secretly using git locally on the sly.
The only person who bothered learning git was a summer intern. And he mastered it, so I know it's not that hard if you're still willing to learn.
Knowing a tool also means knowing what not to use:
The designed unit of a (distributed) git workflow is a patch — i.e. a locally rebase-squashed set of cherry-picked commits from development branches, with `git reset --soft` + `git add -p` (or even `git format-patch` + manual editing) used to prune the patch to a minimal size. Everything you do in your local repo should be with the intention of producing readable patches for code review (whether that patch is then done via PR or mailing list.) It's not about creating a pretty history (retroactive); it's about making it easy on the people who will discuss and reformulate your changes, one at a time, before accepting them upstream.
To be clear, you can do whatever you want when your git workflow isn't distributed (i.e. if you're committing to only your own private projects, not proposing changes to other people's projects.) But if your workflow isn't distributed, then why be opinionated about git? You can simplify your life at that point by using something with central-repo-oriented semantics, e.g. Subversion. There's no rebasing in Subversion. :)
Sometimes features do require large changes. But usually you can break a feature into different parts (e.g. database, backend, frontend) and merge them in separately.
> But usually you can break a feature into different parts (e.g. database, backend, frontend) and merge them in separately.
So you've already written all that code, because you couldn't get anything to "work" for end-to-end testing until you wrote all parts of it. The patchset as a whole is inherently large.
Now what? How do you "break [the] feature into different parts" when it's already all written and committed on a WIP branch?
That's right: cherry-picking and rebasing.
The GP is arguing against bothering with this process. Presumably because git-rebase(1) is unintuitive to them, and they don't realize that you should start this workflow with a copy of your branch, or a new branch with cherry-picked commits from your WIP branch, to guarantee non-destructive rebasing. Like making a copy of a layer in Photoshop. (Yes, you can always restore your branch from the reflog, so it's technically always non-destructive; but `git checkout -b foo` is something you learn in Chapter 1 of the Git book.)
This is why you can't generally share work using a rebase workflow.
It is not a big deal in practice in most every case, but in a version control system it is a little bit odd that rolling back such a fundamental operation isn't a first class feature.
`git reflog` to get the old commit ID, and then `git reset --hard <commit>`. Seems more like "basic everyday git operations" than "some delicate git surgery".
The reflog tracks rebase commit history. No surgery required.
>This is why you can't generally share work using a rebase workflow.
Rebase of public facing commits is not discouraged due to data loss. It is discouraged due to the possibility of someone creating change sets off the published work, and then the update re-writing the history to change the merge-base, requiring a re-merge of their changes.
Here is a script (just 3 lines) that tells git bisect to ignore commits in the feature branches, so you can bisect only the commits (usually the merge commits) in the main branch. Best of both worlds.
https://quantic.edu/blog/2015/02/03/git-bisect-debugging-wit...
There's a reason git came into existence for linux kernel development. The linux kernel is a project so massive and so decentralized that it needed a fitting tool to be able to tame the chaos. And git did that perfectly.
Out of curiosity though, what to you is a better source control system?
Squash merges are perfect to me for the bulk of PRs- atomic test-passing iterations on the working product. Exactly what I want to see in my history. Useful for bisection. Good for reviewing line-based code changes as I can find all the related work for that feature.
They don't seem appropriate for long lived feature branches, or merging into release branches, but those aren't really being discussed here.
In my experience, only the simplest PRs boil down into what's logically a single commit. Many PRs are simple, sure, but often you end up with bunch of logically connected atomic changes instead.
Let's take Mesa, an established and fairly high quality project, as an example. Look at its open MRs.
You can find bunch of single commit MRs, but some of them consist of approx. 2-4 commits, all of them with proper commit message. See for example https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19... or https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19.... It wouldn't make any sense to squash them when merging.
You can also get monster MRs consisting of 10-20 commits, like https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19... or https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19.... Splitting them out into separate MRs would serve nobody, only increasing noise and review turnaround time. Squashing them would lose a lot of useful information that you definitely want to retain for things like blame or bisect.
Now, Mesa actually doesn't utilize git as well as it could - it doesn't encode the commit's relation to merge request in any way other than commit message (`Part-of:` tag). Personally, I would merge a rebased branch using `git merge --no-ff` option, which would create a merge commit. This way, you get best of both worlds: by using tools like `git log` or `git bisect` with `--first-parent` flag you get what's essentially a list of merged MRs, filtering individual commits out; and if you don't add that flag, you get every single individual commit considered, useful for stuff like `blame` or single file `log`.
Also, before pushing a MR for review, my work branch is usually a mess. Lots of poorly divided up commits, without proper commit messages, sometimes undoing each other. `git rebase -i`, with squashing and rewording, is part of my everyday workflow. It allows me to use git as my personal undo and "let's-try-it-in-CI" tool without putting that baggage onto the reviewer. I get to be as messy as it's useful during my work, and the reviewer gets properly curated list of commits that's ready to be merged into the repository as-is. It's a win-win.
Not using rebases when working with git is fine when you work alone or when you're just learning how to use git, say, during a university project or internship. Otherwise, you're doing yourself a big disservice if you don't put that tiny effort into getting comfortable with tools you're using every day in your work.
So far I had never lost data ever with git, just confusing git situations from people who never rebased, but still shoot into their own foots with duplicate commits added by helplessly merging around multiple branches too much, all with much too many "fix typo" commits and then unresolvable conflicts :D
(Oh, and btw, when people end up there and I'm asked to get them back to sanity, it usually involved rebasing or cherry-picking them out of their messes).
Nobody who understands git will ever lose data, because once committed you can never lose it (it's in the reflog). Indeed, even just adding a file means you will never lose it, although it's not as convenient as having an actual commit.
So yeah, you kind of revealed the anti-rebase case quite tellingly there. It's for people that understand git so poorly that they regularly shoot themselves in the foot and lose work or make other similar mistakes.
> Most of the arguments in favor of rebase are by people fanatical about having a git history organized just so. It’s not worth the headache and effort. PRs are a better unit of work than commits in practice.
PRs and good git commit history are not mutually exclusive. But there are many drawbacks of trying to make PRs themselves your source of truth. A big one being that it's not actually stored in git, so if you ever migrate from github to gitlab or some other system, that context is gone.
> Configure GitHub or whatever you use to squash merge only and you’ll be good.
See, now this becomes even more absurd. What's your fear of rebasing if you're going to do the equivalent of a `git rebase -i` upon every merge anyway?
This is a very confusing and nonsensical ideology.
For those who want to improve their grasp of git, I highly recommend https://git-scm.com/book/en/v2. That book changed the game for me, because I finally understood how to visualize git history in terms of the DAG, and furthermore learned about how git actually works under the hood (blobs and the like) which made me confident I would never lose anything I've ever added/committed ever again.
Request is committed to the repo on acceptance. Closed are useless.
> What's your fear of rebasing if you're going to do the equivalent...
The system takes care of the details without incidental complexity or errors.
> This is a very confusing and nonsensical ideology.
Pretty simple, folks are trying to get shit done. Not screw around with tools. One or two clicks where someone else did the hard work wins every time.
I'm trying to get stuff done, not screw around with the Github UI. `git pull --rebase main` beats clicking around in a browser.
Seems to be a bit of an OCD compulsion.
Most of the arguments in favor of rebase are by people fanatical about having a git history organized just so. It’s not worth the headache and effort. PRs are a better unit or work than commits in practice.
Configure GitHub or whatever you use to squash merge only and you’ll be good.
Since moving to this workflow I’ve had zero issues losing data due to a confusing git situation.