Except it can be the result of 10 squashed commits.
Without Squash, the main branch history becomes a timeline of your mental struggle.
With Squash, the main branch becomes a catalog of features delivered.
No body needs to take a trip on the struggle bus with me...
For the same reason you have your production history instead of zip file with code)
>while presenting a nice clean set of changes at the end of it
The set, yes, not a single squashed commit.
>The branch is a scratchpad, you should feel empowered within your own branch, rebase
Yes, amend, fixup, rebase. Make it a nice set of small commits.
Which is an argument against GitHub, not clean commit history
My preference for rebasing comes from delivering stacked PRs: when you're working on a chain of individually reviewable changes, every commit is a clean, atomic, deliverable patch. git-format-patch works well with this model. GitHub is a pain to use this way but you can do it with some extra scripts and setting a custom "base" branch.
The reason in that scenario to prefer rebasing over "merging in master" is that every merge from master into the head of your stack is a stake in the ground: you can't push changes to parent commits anymore. But the whole point of stacked diffs is that I want to be able to identify different issues while I work, which belong to different changes. I want to clean things up as I go, without bothering reviewers with irrelevant changes. "Oh this README could use a rewrite; let me fix that and push it all the way up the chain into its own little commit," or "Actually now that I'm here, let me update dependencies and ensure we're on latest before I apply my changes". IME, an ideal PR is 90% refactors and "prefactors" which don't change semantics, all the way up to "implemented functionality behind a feature flag", and 10% actual changes which change the semantics. Having an editable history that you can "keep bringing with you" is indispensible.
Debugging history isn't really related. Other than that this workflow allows you to create a history of very small, easily testable, easily reviewable, easily revertible commits, which makes debugging easier. But that's a downstream effect.
But the main benefit proponents or rebase say its for keeping the history clean which also makes it easier to pinpoint and offending commit.
Personally, a clean commit history was never something that made my job easier.
> Other than that this workflow allows you to create a history of very small, easily testable, easily reviewable, easily revertible commits, which makes debugging easier. But that's a downstream effect.
I would agree that it is important for commits to go from working state to working state as you are working on a task, but this is an argument for atomic commits, not about commit history.
How do you define "clean"? I've certainly been aided by commit messages that help me identify likely places to investigate further, and hindered by commit messages that lack utility.
In the context of merge vs rebase, I think "clean" means linear, without visible parallel lines. Quality of commit messages is orthogonal. I agree with the poster that this particular flavor of "clean" (linear) has never ever helped me one bit.
I think the obsession with a linear master/main is a leftover from the time when everyone used a centralized system like svn. Git wasn't designed like that; the Linux kernel project tells contributors to "embrace merges." Your commit history is supposed to look like a branching river, because that's an accurate representation of the activity within your community.
I think having a major platform like github encourages people to treat git as a centralized version control system, and care about the aesthetics of their master/main branches more than they should. The fact the github only shows the commit history as a linear timeline doesn't help, either.
if you look at it as in investment in understanding the code base more than just closing the ticket as soon as possible, then the 'lets see what really going on here' approach makes more sense.
Me neither, for what is worth. But even if the idea is "when in order to figure out this issue, you have to go to the history", a linear history and a linear log never helped me either. For example, to find where a certain change happened to try to understand what was the intent, what I need is the commit and its neighbors, which works just as well with linear vs branching history because the neighbors are going to still be nearby up and down, not found via visual search.
I think the question was about situations where you were glad to rebase, when you could have merged instead
All the commits for your feature get popped on top the commits you brought in from main. When you are putting together your PR you can more easily squash your commits together and fix up your commit history before putting it out for review.
It is a preference thing for sure but I fall into the atomic, self contained, commits camp and rebase workflows make that much cleaner in my opinion. I have worked with both on large teams and I like rebase more but each have their own tradeoffs
especially since every developer has a different idea of what a commit should be, with there being no clear right answer
EDIT: I may have read more into GPs post but on teams that I have been on that used merge commits we did this flow as well where we merged from main before a PR. Resolving conflicts in the feature branch. So that workflow isn’t unique to using rebase.
But using rebase to do this lets you later more easily rewrite history to cleanup the commits for the feature development.
git log --oneline --graph --first-parentGit won, which is why I've been using it for more than 10 years, but that doesn't mean it was ever best, it was just most popular and so the rest of the eco system makes it worth it accepting the flaws (code review tools and CI system both have much better git support - these are two critical things that if you use anything else will work against you).
What code review tools do you prefer?
- Reshuffle commits into a more logical order. - Edit commit subjects if I notice a mistake. - Squash (merge) commits. Often, for whatever reason pieces of a fix end up in separate commits and it's useful to collect and merge them.
I'd like to make every commit perfect the first time but I haven't managed to do that yet. git-rebase really helps me clean things up before pushing or merging a branch.
Interactive rebasing to write local history on your working branch is incredibly useful, but also doesn't have anything to do with the "rebase vs merge" conundrum, and as long as you're not pushing to a shared branch, it doesn't have much to do with "erasing other's history".*
If you can look at a working branch (with more than a trivial addition or fix) and not feel the need to do a interactive rebase (once you know how) before making a PR, then you're either a magical 100x unicorn dev that makes every commit the perfect commit, or you cheated and made a new branch and cherry-pick-squashed your way to a clean history.
To answer your question directly, if somewhat glibly, I’m glad I rebased every time I go looking for something in the history because I don’t have to think about the history as a graph. It’s easier.
More to your point, there are times when blame on a line does not show the culprit. If you move code, or do anything else to that line, then you have to keep searching. Sometimes it’s easier to look at the entire patch history of a file. If there is a way to repeatedly/recursively blame on a line, that’s cool and I’d love to know about it.
I now manage two junior engineers and I insist that they squash and rebase their work. I’ve seen what happens if they don’t. The merges get tangled and crazy, they include stuff from other branches they didn’t mean to, etc. the squash/rebase flow has been a way to make them responsible for what they put into the history, in a way that is simple enough that they got up to speed and own it.
In this case, rebasing is nice because our changes stay in a contiguous block at the top (vs merging which would interleave them), so it's easy for me and others to see exactly where our fork diverges.
Are you saying that you've never used git bisect? If that's the case, I think you're missing out.
It is a tragedy that more people don't know about it.
If the contributor count is high enough (or you're otherwise in a role for which "contribution" is primarily adjusting others' code), or the behaviors that get reported in bugs are specific and testable, then bisect is invaluable.
If you're in a project where buggy behavior wasn't introduced so much as grew (e.g. the behavior evolved A -> B -> C -> D -> E over time and a bug is reported due to undesirable interactions between released/valuable features in A, C, and E), then bisecting to find "when did this start" won't tell you that much useful. If you often have to write bespoke test scripts to run in bisect (e.g. because "test for presence of bug" is a process that involves restarting/orchestrating lots of services and/or debugging by interacting with a GUI), then you have to balance the time spent writing those with the time it'd take for you to figure out the causal commit by hand. If you're in a project where you're personally familiar with roughly what was released when, or where the release process/community is well-connected, it's often better to promote practices like "ask in Slack/the mailing list whether anyone has made changes to ___ recently, whoever pipes up will help you debug" rather than "everyone should be really good at bisect". Those aren't mutually exclusive, but they both do take work to install in a community and thus have an opportunity cost.
This and many other perennial discussions about Git (including TFA) have a common cause: people assume that criticisms/recommendations for how to use Git as a release coordinator/member of a disconnected team of volunteers apply to people who use Git who are members of small, tightly-coupled teams of collaborators (e.g. working on closed-source software).
I actually think that is the most useful time to use bisect. Since this is a situation where the cause isn't immediately obvious, looking through code can make those issues harder to find.
For example, take a made up messaging app. Let's call it ButtsApp. Three big ButtsApp releases releases happened in order that add the features: 1) "send messages"; 2) "oops/undo send"; and 3) "accounts can have multiple users operating on them simultaneously". All of these were deemed to be necessary features and released over successive months.
Most of the bugs that I've spent lots of time diagnosing in my career are of the interacting-known-features variety. In that example, it would be "user A logs in and sends a message, but user B logs in and can undo the sends of user A" or similar. I don't need bisect to tell me that the issue only became problematic when multi-user support was released, but that release isn't getting rolled back. The code triggering the bug is in the undo-send feature that was released months ago, and the offending/buggy action is from the original send-message feature.
Which commit is at fault? Some combination of "none of them" and "all of them". More importantly: is it useful to know commit specifics if we already know that the bug is caused by the interaction of a bunch of separately-released features? In many cases, the "ballistics" of where a bug was added to the codebase are less important.
Again, there are some projects where bisect is solid gold--projects where the bug triage/queue person is more of a traffic cop than a feature/area owner--but in a lot of other projects, bugs are usually some combination of trivially easy to root-cause and/or difficult to fix regardless of whether the causal commit is identified.
This is especially true if you have multiple repos and builds from each one, such that you can't just checkout the commit for build X.Y.Z and easily check if the code contains that or not (you'd have to track through dependency builds, checkout those other dependencies, possibly repeat for multiple levels). If the date of a commit always reflects the date it made it into the common branch, a quick git log can tell you the basic info a lot of the time.
I like to keep a linear history mainly so I don't have to think very hard about tools like that.
Besides testing for a perf slow down, any other use cases for git bisect + rebase?
You can write a test (outside of source control) and run `git bisect good` on a good commit and `git bisect bad` on bad one and it'll do a binary search (it's up to you to rerun your test each time and tell git whether that's a good or a bad commit). Rather quickly, it'll point you to the commit that caused the regression.
If you rebase, that commit will be part of a block of commits all from the same author, all correlated with the same feature (and likely in the same PR). Now you know who you need to talk to about it. If you merge, you can still start with the author of the commit that git bisect found, but it's more likely to be interleaved with nearby commits in such a way that when it was under development, it had a different predecessor. That's a recipe for bugs that get found later than they otherwise would've.
If you're not using git history to debug, you're probably not really aware of which problems would've turned out differently if the history was handled differently. If you do, you'll catch cases where one author or another would've caught the bug before merging to main, had they bothered to rebase, but instead the bug was only visible after both authors thought they were done.
not true. You can use
git bisect run script-command arguments
where script-command is a ... script that will test the result of the build.Rebasing on main loses provenance.
If you want a clean history doing it in the PR, before merging it. That way the PR is the single unit of work.
Well if I have a diff of the PR with just the changes, then the PR is already a "unit of work," regardless of merge or rebase, right?
Any workflow that has a review process uses rebase. FULL STOP.
If you don't have your code reviewed and you push code to a shared repo, fine, don't use rebase if you don't want to.
Of course a readable code history aids in debugging. Just as comments and indentation do. None of these are technically necessary, but still a good idea.
Of course running the rebase command doesn't guarantee a readable commit history, but it's hard to craft commits without it. Each and every commit on linux-kernel has been rebased probably a dozen times.
Most committers don't really understand remotes, much less rebasing.
If I diff against master, I see changes in 300+ files, when I've only changed 5 (because other people have changed 300+ files.)
> Fundamentally, I do not debug off git history.
Neither. The usual argument I hear against rebase is that it destroys history. Since I don't debug off git history, I'm quite happy to destroy it, and get back to diffing my 5-file changes against (current) master.
You’ve never run a bisect to identify which commit introduced a specific behavior?
This is when I’ve found it most useful. Having commits merged instead of squashed narrows down and highlights the root problem.
It’s a rare enough situation I don’t push for merge commits over squashed rebases because it’s not worth it, but when I have had to bisect and the commits are merged instead of squashed it is very very useful.
Those commit authors are who I noted as clear thinkers and have tracked over my career to great benefit.
I'm really sorry. Using bisect and log -S saved hours of code debugging
Not once have a ever debugged a problem that benefited from rebase vs merge. Fundamentally, I do not debug off git history. Not once has git history helped debug outside of looking at the blame + offending PR and diff.
Can someone tell me when they were fixing a problem and they were glad that they rebased? Bc I can't.