Live data from Hacker News

Fortunately, I don't squash my commits

blog.ploeh.dk

151–160 of 333 posts

Re: Fortunately, I don't squash my commits

#152
post #93

Hijacking the top thread to make an important point: - "Squash your commits" folks - yes, it's good to be able to revert a commit and remove entire features and have a readable commit history. - "Make small granular commits" folks - yes it's good to be able to bisect and see where exactly some behaviour changed. Rather than repeat these points (which are both true), there's a better question to be asked: Should there…

This response [0] by avar shows you can get both by using the min/max parents flags, to either see only merge commits or only code commits:

[0] https://news.ycombinator.com/item?id=24687027

Re: Fortunately, I don't squash my commits

#153
post #77

The reason to squash commits is more than just keeping your commit history read-able, it's about making easy to revert a feature and being able to keep history in a way that makes it simple to revert a change if you run into issues. If I rollout a rewrite of an endpoint and run into a weird issue in the QA environment, I'm a simple git revert away from fixing the issue. If I had spread that endpoint across 25 commits…

> If I rollout a rewrite of an endpoint and run into a weird issue in the QA environment, I'm a simple git revert away from fixing the issue I'm firmly of the belief that any benefits that squashing brings would be better achieved with better tooling, rather than by re-writing history and throwing away potential debugging information. In this case, what you need is for git to make it easier to revert 25 commits in on…

Also, can't you just revert the merge commit?

Re: Fortunately, I don't squash my commits

#154

Earlier quoted context omitted.

The fix is very easy: forbid fast-forward merges, and then you can always revert the merge commit of particular feature branch. As for cleanliness of history, everything should be as simple as possible, but not simpler. Squashing and rebasing is destroying history, which often could be valuable, as OP shows.

forbid fast-forward merges?!!?!

Fast forward merges lose track of the fact that these commits you are merging are, together, doing a coherent thing.

Re: Fortunately, I don't squash my commits

#155
post #150

The most striking thing in this story for me has nothing to do with commit squashing. Faced with something that suddenly stopped working, the developer went on a wild goose chase, first decoding their JWT -- presumably the same one that "used to work" -- then looking for possible framework bugs or misconfiguration, before looking at their own code, the single most likely place that the bug would be. They even linked…

"went on a wild goose chase" Because 19 times out of 20, that "wild goose chase" finds the bug faster. As there is no perfect debugging methodology, sometimes whatever method you use will go wrong and you'll end up on the bottom of your list of things to check, or worse, right off the bottom of the list. (Those are some bad days.) That is not, itself, proof that your list is broken. After all, the author found this a…

Starting with your own code is going to find the bug faster far more of the time than starting with "maybe the JWT got randomly broken or my JWT library is broken" or "maybe ASP.NET is broken".

Re: Fortunately, I don't squash my commits

#156
post #58
post #2

Do people out there actually squash commits? Granted, I didn't change many work places in my career, but at no place where I worked people squashed commits. What's even the point of it? It's not like people routinely read the commit history, and when they do, they really would like a complete story, not 20 gargantuan commits that contain 3 years of development.

I often do intermediary commits that don't compile or break something significant, only to make sure that I don't lose the code. When that happens I always squash my commit afterwards once the code is in a usable state. The alternative is making bisecting harder which is not something that I want. I want every commit to compile and be testable individually. That definitely doesn't mean that I think it's a good idea t…

I'm a bit confused on your comments here. You state "I often do intermediary commits that don't compile ... to make sure that I don't lose the code" And follow that with "I want every commit to compile and be testable individually."

Re: Fortunately, I don't squash my commits

#157
post #89
post #77

Earlier quoted context omitted.

> If I rollout a rewrite of an endpoint and run into a weird issue in the QA environment, I'm a simple git revert away from fixing the issue I'm firmly of the belief that any benefits that squashing brings would be better achieved with better tooling, rather than by re-writing history and throwing away potential debugging information. In this case, what you need is for git to make it easier to revert 25 commits in on…

If git has a concept of branches like mercurial has it would be a lot easier as you can actually see what branch your commits attached to. (there are pros and cons of both approaches - this is a con of the git approach, I'm not knowledge about enough about esoteric details to comment on if git actually made a bad choice or just a compromise)

Thankfully most Git hosting websites do have this concept. You can revert a PR whole using github, etc

Re: Fortunately, I don't squash my commits

#158
post #90

Earlier quoted context omitted.

If you squash all the merge requests, you get ONLY merge commits.

A 'merge commit' is the commit that ties together two strands. * merge commit |\ | * branch work | | | * branch work |/ * If you squash to merge, typically you're also going to rebase it (equivalently, if it's more familiar, cherry-pick the squash onto the branch your 'merging' it into). * squash cherry-picked / rebased | * both branch works squashed | * | branch work | | | | * | branch work |/_/ * (In this case the…

I know. It means that the only commits left are the ones that originally where merge requests, and you loose the rest of the history.

Re: Fortunately, I don't squash my commits

#159
post #110
post #55

Earlier quoted context omitted.

Programmers can have the best of both worlds. Use granular commits on a local branch and squash merge into shared branches. That way one gets clean shared history while preserving local work history.

The problem with this approach is the local branch is no longer represented in the shared branch. So if I'm working on a larger feature and want to PR an intermediate part and continue working, I'm in for a bad merge. If I want to merge my hotfix topic branch into both the release and the master branch, their commits won't match so I can't check if it's present in both automatically. If a topic branch is left up inst…

> I desperately wish git had a "group commits" feature that let me manage a cluster of related commits as a single commit for the purposes of history-viewing, reverting, and cherry-picking.

Maybe you can do something similar to that with git-replace?

Otherwise, you could just tag your commits by putting something in the commit message and use `git grep` to search for those commits. Then you could just build a small helper script that 1. greps for a tag 2. loops over the found commits 3. rewinds them or whatever and 4. squashes the resulting commits.

Dunno, there's a bunch of other ways depending on how exactly you want it. But I agree that grouping commits would be pretty cool :D

Re: Fortunately, I don't squash my commits

#160

I never understood the need to squash commits (or rebase). If you do merge requests and use merge commits (like GitHub or gitlab do). A "nice" history is a small script away. It should even be a part of the GitHub/gitlab gui. Do not loose information about the development history!

Hi, Developer Evangelist at GitLab here. I would say, it depends on the workflow, unfortunately there is not right or wrong here. I'll try to share some situations of my development experience in the past years, also as Git/GitLab trainer:

## Squash

I often start in a feature branch with a new proof of concept, or other code which is persisted in several commits. Sometimes I'll iterate on a few things, like testing a change in a GitLab CI yaml, and checking whether it works. Or a different compiler flag to enable faster package builds. Or a refactored function which needs to run all the e2e tests to prove the performance gain.

These changes may, or may not work. When they do not work, I'll reset the commits - either soft to keep the changes, or hard to throw away the attempt. This follows a changed history and force push into the remote branch. In case of a shared branch, message colleagues with "git fetch && git reset --hard origin/branchname".

Within pair programming sessions, we often left with commits like "Add REST API HTTP server, WIP 2" in branches and depending on the availability, either one of us continued. At a certain point in development time, we decided to squash and amend the commits. Sometimes not all of them, as rebase/squash also allows you to do the following:

c1 s \

c2 s /

c3 p

c4 s \

c5 s /

Which squashes c1+c2, leaves c3, and squashes c4+c5 again. You can navigate into this on the CLI with "git rebase -i HEAD ~5".

## Rebase/Merge

Short-lived branches which are quickly merged back to the main branch shouldn't cause problems with a broken deployment. In case you get a task assigned where the main branch is far beyond (say, 100 commits or more), it may be the case that

- Branch and merge request works fine, CI/CD pipelines are green - Changes in the main branch which affect your feature.

These changes can be

- Function interfaces renamed, or not existing. Easy to fix upon rebase, build/run does not work anymore. - Runtime changes, for example, queries take longer roundtrip due to a refactor. Your feature only takes the old behaviour into account, and increases the runtime complexity. Or it consumes 10x memory resulting in OOM crashes later.

The last change may not be immediately visible, as it involves staging environments and application performance monitoring results.

### Merge without Rebase

If said changes occur, and the rebase did not happen, the green CI/CD MR is merged back to the main branch. Depending on the releases, you either roll into production, or after days/weeks/months, a new release is cut.

At that point, the regression may be seen in the main branch, and cause delayed analysis and debugging. Often times on-call alerts and all the debug fun which may lead to burnout (been there myself).

### Merge Request with Rebase

During the final review, and prior the merge, the changes are rebased against the latest base in the main branch, to see if they compile or any other influences.

A rebase puts the existing commits onto a new commit base, which influences the calculated checksums. Therefore all commits are newly generated, the author date is preserved with changing the commit date.

### Merge Commits

There are different opinions on them. One of them is to always rebase the MR and then do a merge with a commit. Rationale: Even without GitLab/GitHub/etc. you can reliably see the git graph on the CLI or with other visualization tools.

https://gitlab.com/dnsmichi/dotfiles/-/blob/main/.gitconfig#...

I've recently seen the possibility to reference a PR/MR to a commit as the merge-from-branch reference, without the dedicated merge commit. This can be handy to avoid it, with using GitLab/GitHub/etc. to store this detail in their database. It also is a vendor lock-in in a way, that the native "git clone" does not provide this information for you in Git's database.

That being said, I used to dislike merge commits. With enriched details, and CLI work, I now prefer them again. Git commits as datasource are valuable, and they can be shown/parsed in any environment.

### Rebase, Merge, ... large environments?

This can of course get more complex, with fast moving main branches and lots of merges which depend on each other, and should not reach the main branch. Instead, you'd want them to be queued and tested. We experience that at GitLab quite often, and have created so-called "Merge Trains" which ensure that all MRs in such a queue/train are taken into account: https://docs.gitlab.com/ee/ci/merge_request_pipelines/pipeli...

## A personal note: The best merge/rebase strategy is nothing without tests

I've been working on a monitoring tool in the past which includes distributed environments, and often needed to fix bugs with memory leaks or other performance issues in multi-threaded scenarios. Things you do not see immediately when the MR/PR is green. There was one commit which caused a OOM crash after 3 days of runtime, but only in cloud environments with >100 satellite nodes.

The turnaround was to bisect all the commits, and run each of them in production for 3 days until the crash occurred. IIRC we had 1,200 of them to do in a binary search.

Now the question is:

- Fewer squashed commits - More development history

In this case, fewer commits would have unveiled the error sooner. The resulting commit would be larger and harder to debug & fix though.

In the end, it did not really matter. The thing which would have helped: There was no reliable test environment coupled to CI, CD which ensured to run specific commits & MR/PR in dedicated scenarios and alert of breaking changes soon enough - before the release happens.

## Conclusion

One thing which greatly helped: Looking how others do it, Open Source projects and customer success stories and webinars, online training sessions. Even though you may not adopt the workflows, trying them out is a good way to learn. For instance, "trunk based development with feature flags" is something different to well-known branching models for me, I needed to try them out first to change my opinion. They are indeed useful for certain scenarios.

While committing changes, and keeping them throughout un-squashed MRs, I always remember that I will be highly likely debugging the changes later on. Or someone who finds the MR reviewed by myself, documenting every thought or idea in a commit or MR comment can help.

Some more tips and exercises are discussed in an OSS training I created in the past: https://github.com/NETWAYS/gitlab-training/releases/tag/v2.5...

Post reply on HN