9 ms·
Ah! My people. I, too, much prefer a rebase-heavy workflow. It allows me to both have a dirty "internal" history and clean up for publication. As a side-effec
by AceJohnny2 2y ago
Ah! My people.
I, too, much prefer a rebase-heavy workflow. It allows me to both have a dirty "internal" history and clean up for publication.
As a side-effect, it also makes me comfortable having a mostly linear-history for what I publish, as opposed to a many-branched, merge-heavy one, which I dislike, and makes history confusing.
I reject the argument that a no-rebase, merge-only history "preserves the true history of how commits were created", because I believe that is irrelevant. What is relevant is what the tree looks like once the merge (or rebase) lands.
Should a merge conflict arise, in a rebase workflow the conflict resolution is folded into the rebased commit, so it looks like it was fine all along. In a merge workflow, the fix is in the separate merge commit. In both cases you still have to handle the merge conflict. And in my opinion it is not significant for the merge conflict resolution to be separate from the original commit itself because, again: what's important is the final state of the repo.
- AceJohnny2 2y agoI'll add what should be obvious to any seasoned git user: rebase is only possible for "private" commits. If the commits were published, then merge is the only solution, because otherwise with a rebase you will "change (git) history" and break people's repos that have yours as upstream. I recommend reading this 2008 exchange between top Linux developers learning to use git, and Torvalds's... characteristic language when talking about rebasing a "public" repo: https://www.yarchive.net/comp/linux/git_rebase.html https://www.yarchive.net/comp/linux/git_rebase.html (I'm putting "private" and "public" in quotes because they're really on a spectrum)
- ruraljuror 2y agoI like your point. The exception is if the project you work on is itself downstream, in which case maintainers will rebase those “published” commits, probably employing the same technique they use to keep their local development branches up-to-date with the downstream project.
- MrDarcy 2y agoIn practice it’s fine to rebase and force push to your own published branch, even when it’s an open PR. Just mark it draft or otherwise communicate when it’s no longer a moving target.
- singpolyma3 2y agoEspecially when it's an open PR. That's effectively essential in order to, say, address feedback
- spankalee 2y agoI try not to rebase and force push for branches under active review though. It makes it much harder for the reviewer to see the changes that have happened since they last reviewed.
- argulane 2y agoThat's only a problem when using GitHub. GitLab and Gerrit correctly version such force push PR updates and provide a nice view of what has changed.
- everybodyknows 2y agoI version-number PR branches for upstreams on GitHub. If my branch 'for-upstream-13.0' does not apply cleanly on top of upstream 'main', I sync my fork's 'main' to upstream in GitHub's Web GUI, fetch to my desktop, and build a new 'for-upstream-13.1' on top, with the help of git-cherry-pick. Might need a new PR. All history is preserved, both on GH and locally.
- PaulDavisThe1st 2y agoIf you work on a branch also worked on by others, then yes, rebase is "only" possible on private commits. But if you work on a feature branch, you can publish that branch as long as everybody else understands that it is yours and nobody should push to it. Then you can safely git push --force to the feature branch so that others can (a) see what you're up to (b) test the results. When you're done, you can do a final (or only) rebase against the target branch then merge to that branch.
- smcameron 2y ago> Then you can safely git push --force What I hate about this workflow is it teaches you to git push --force. Then one day, you're in the wrong window and you accidentally git push --force on master. Much prefer a workflow where you never git push --force
- necessary 2y agoGit hosting platforms generally have controls that allow you to prohibit force pushes on protected branches (i.e. master)
- The_Colonel 2y agoThis doesn't fix the problem since you still can do a lot of damage doing that on a (perhaps wrong) feature branch.
- SOLAR_FIELDS 2y agoIt certainly diminishes it significantly. Very few people are usually collaborating on the same branch together that isn’t the main branch in most orgs. So the chances of you destroying yours or someone else’s work that way is pretty low. You can also branch protect any arbitrary branch, at least on GitHub, though I’ve never been in an org that protects branches other than the main one, besides an org that used release branches. I’ve also never seen someone clobber someone else’s feature branch, though it probably does happen. Much more often people are accidentally clobbering their own branches. The ability to rewrite history on feature branches is powerful in a good way and slots right into the way Git is philosophically designed. I would probably not be interested in removing that feature to prevent the rare case that someone footguns themselves or someone else
- forrestthewoods 2y ago> rebase is only possible for "private" commits. This is false. Well, it can be false. Git sucks and makes it harder then it needs to be. It’s relatively easy to have multiple people working on a feature branch that is continuously rebased. Meta’s Mercurial-like VCS system automagically stores 100% of commits in the cloud. Feature branches are anonymous rather than named. It’s all just a tree of commit hashes. Having multiple people work on one “branch” requires some basic communication as to what is considered “tip”. But since it’s all anonymous there’s no issues with different people incrementing a named branch to different commits. Honestly it’s pretty simple and easy. Git makes it harder than it actually is.
- rmgk 2y agoAs far as I can tell, what is really meant by “rebase is only possible for "private" commits.” is that for public commits, rebasing would require to coordinate with everyone interested in that branch. This seems to be very similar to what you say with “requires some basic communication as to what is considered ‘tip’” Requiring coordination (or a constrained model of allowed changes) when modifying things (such as what the tip/branch points to) is a general principle unrelated to git and applies to every workflow. That said, I do understand that Meta’s centralized tool is more useful for your usecase.
- forrestthewoods 2y ago> I do understand that Meta’s centralized tool is more useful for your usecase. One of my chief Git complaints is that 99.9% of projects are de facto centralized on GitHub. Genuinely decentralized projects are vanishingly rare. The way Git auto-advances branch tags causes a lot of pain. Having lots of people commit to a shared feature branch that has lots of rebasing is quite easy when the “tip” is infrequently updated. Each person thinking they can declare the new tip with every commit is the source of pain.
- rmgk 2y agoAgain, I see where you are coming from, and I do agree that a lot of discussion about Git (and it’s workflow) is really about GitHub (and it’s workflow). But even when using GitHub as the hosting service, every time you work on a local branch (this includes main/master) you are working on something purely local that will not conflict with what anyone else is doing. It’s only by pushing/pulling that tracking branches are automatically updated, which seems to correspond to the operation that you would refer to as updating tip. As the rest of the discussion is this topic seems to indication, people do work on these “private” branches a lot, and do rebase/modify them freely to create a history as they like before publishing that history (at which point, you would require coordination with everyone who saw that to change it again). As far as I can tell, what the Meta tooling seems to offer is that you can see the “kinda private” commits of other people, if I understand correctly. That does sound indeed useful, but also out of scope for Git – rather part of some further UI that displays such information conveniently.
- forgingahead 2y agoThanks for sharing the link. I'm pulling out the valuable summary at the end. I'm not sure what you're alluding to with his language, but it's a clear and articulate post that junior devs, or folks used to working solo, should see to understand the thought process behind it. === In other words, you really shouldn't rebase stuff that has been exposed anywhere outside of your own private tree. But within your own private tree, and within the commits that have never seen the light of day, rebasing is fine. (And yes, there are exceptions. If it's a clear "throw-away tree" all the rules go out the window, of course, as long as everybody involved knows it's a throw-away tree, and know that if they pull it they have to synchronise 100% with you - so within a very tight-knit case or within a very specific small detail that is actively being worked on, those rebases with cleanups make tons of sense). ===
- quectophoton 2y ago> I reject the argument that a no-rebase, merge-only history "preserves the true history of how commits were created", because I believe that is irrelevant. What is relevant is what the tree looks like once the merge (or rebase) lands. That's kind of the point though: being reasonably sure that a commit contains a tree that the committer had seen at some point, instead of making up history with commits that contain trees that the committer never saw at any point at all. When someone rebases `n` commits, experience has taught me I can't trust any commits other than `HEAD`; chances are any commit printed by `git log "HEAD~${n}..HEAD^"` was never checked out by anyone, much less tested at all. CI pipelines also usually run only against HEAD at the moment of push, so if someone pushes `n` commits, then `n-1` are usually ignored by CI pipeline. Modifying options for compiler or linter or formatter checker; adding a new dependency or updating an existing dependency's version; changing default options for the project. Stuff like that might make those commits useless, and if someone notices a problem in HEAD after rebase, and decides to fix it, even if the fix is moved to the earliest possible point, nobody would bother re-testing all those n-1 commits after the fix was added, leaving broken commits useless for git bisect. So I agree that rebase is nice. How most people use it, though, not so nice.
- rednafi 2y agoThis assumes the rebasing will be done in a shared branch. Two rules of rebasing: 1. Never rebase a shared branch 2. Never break rule 1
- lmz 2y agoNo, that describes rebasing and preserving the intermediate commits. Of course, if you squash into one commit at merge time, this won't happen.
- osigurdson 2y agoI think most people these days just look at PRs. Everything else is largely noise.
- saagarjha 2y ago
- rictic 2y agoSure it looks nice, but it's a fake history. After a rebase you have commits where no one's ever run the tests, no author ever intended to get the repo into that state. Hell, most likely no one knows if the code even compiles. It's assuming that that merge conflicts will never be too difficult, and people won't make mistakes in resolving them. If so, too bad, the original commits are lost by the rebase process. (They might or might not be kept in any given clone. No guarantees, good luck trawling through the reflog.) It's corrupting your database because it makes the UI for exploring it nicer. This is the opposite of what we should be doing! If the truth is messy we should build better UIs for exploring it. Add additional information on top of the true history, allow people to group and describe commits. Add more information to get the UI that you want, rather than destroying information because it makes things look cluttered.
- AceJohnny2 2y ago> After a rebase you have commits where no one's ever run the tests, no author ever intended to get the repo into that state. Hell, most likely no one knows if the code even compiles. That is the role of the CI system.
- lmz 2y agoCI will usually only run the latest commit. Even if commit a, b, and c were all tested, the resulting commits a', b', and c' after rebase would usually only have the last one tested.
- skybrian 2y agoSince you shouldn't publish commits that weren't tested, this suggests you should publish only one commit at a time. (Unless you think "works on my machine" is good enough testing. Sometimes it is.)
- lmz 2y agoSo rebase then force push a', wait for CI, push b', wait for CI, push c'? Personally I just squash on merge.
- danlugo92 2y agoHonestly I dont even do history anymore for small projects, I bisect twice a year tops and I have never evee have had to look at a 3 year old commit to figure out a bug, not that the code could'nt be 3 years old but the blame is so tangled at that point..
- stavros 2y agoI've been a developer for twenty four years. I've seen a lot of people have strong opinions about whether to merge or rebase, to squash or not to squash. I haven't seen one single time where it made a difference whether something was merged or squashed, as I've never seen anyone look at commit messages in depth, versus tickets or PRs or bisecting.
- dnadler 2y agoReally? I certainly have used commit messages and seen others do the same. Perhaps this is more an indictment of the quality of the commit messages than anything else. In my experience, rebase and squash makes it easier to collect work into meaningful groups and thus write more helpful/informative commit messages. I can think of a few times off the top of my head when I referred back to a detailed commit message in a repo to understand why a change was made.
- stavros 2y agoIf I'm making a change that people are likely to wonder about, I tend to add comments. Basically, anything that's not obvious tends to get a comment, change or no.
- citrin_ru 2y agoI read 'git log -p' often, and linear history makes it so much easier. The same with bisecting. I'm yet to see any practical advantage of not allowing rebase/squash in feature branches. Preserving all history of feature branches is not an advantage to me. The history I care about is the history of the main branch and I don't want to see it splint into many tiny commits, especially not into commits looking like add/fix/fix/fix/fix where at all point except the last the code is broken.
- klysm 2y agoThe problem I run into is when a developer merges the main line branch into their feature branch repeatedly to get new changes. Now your branch is completely tangled up and difficult to change
- rurban 2y agoExactly. The only true history is the clean, properly rebased history with one change per commit, as I want it.
- lr4444lr 2y agoPreach, brutha!
- eschneider 2y agoI generally prefer a rebase-free workflow (mostly due to my upbringing. Long story...) But other than rebasing shared branches, which (with notable exceptions) is a Wrong Thing, it's mostly up to teams to decide on a workflow that gets things done for them. As long as there's a consensus on how to do things, go with god.
- Nullabillity 2y ago> I reject the argument that a no-rebase, merge-only history "preserves the true history of how commits were created", because I believe that is irrelevant. What is relevant is what the tree looks like once the merge (or rebase) lands. Was the bug introduced by the rebase, or was that code always broken?
- singpolyma3 2y agoCode doesn't exist until it is merged, so these are equivalent
- Nullabillity 2y agoErr, what? If I'm trying to fix the PR, the distinction is often a critical starting point for finding the root problem.
- lolinder 2y agoIf your PR is big enough that you're relying on a git bisect to find a bug, that's a problem in its own right. A workflow like what OP is describing (code doesn't exist until it's merged) typically also assumes that your PR is one atomic change, not a whole feature. You'd use feature flags or something similar to decide when to actually release a feature, not the PR process.
- Nullabillity 2y ago> If your PR is big enough that you're relying on a git bisect to find a bug, that's a problem in its own right. Who said anything about bisecting? But yes, sometimes changes are big and I'd rather land them as one cohesive unit that demonstrates how it actually solves the root issue than get stuck down a wrong path because "this is what we already landed the infra for". > A workflow like what OP is describing (code doesn't exist until it's merged) That's not a workflow, it's a misunderstanding of reality.
- ak217 2y agoI love rebasing, and use it most of the time. At work we also enforce squash-merging, which is the only scalable way to prevent low quality commits from polluting the main branch history. While rebasing works most of the time, the problem arises when actually collaborating on feature branches - especially when your collaborator is not confident enough with git to realize when a rebase conflict might lose data. Merging works better in these situations. So while standardizing on rebasing is great for productivity across the org, you also have to watch out for this and make sure developers don't lose the ability to collaborate on branches.
- The_Colonel 2y agoWhat's the point of rebasing when you in the end squash-merge? In my mind the only real benefit of rebasing is that you split your work into a couple of "nice" commits, but if you squash them anyway... Ok, I've seen people doing this to ease the review process and I guess it makes sense sometimes, but to me it's still a largely "not worth it" effort.
- sensanaty 2y agoThe squash merge is for the sanity of master/main, whereas rebase is for the sanity of the reviewer. That's how I look at it at least
- account42 2y agoIf your developers can't manage to create sensible commits then do you really want them to make code changes? Workflows with linear history made up of logical commits "scale" just fine, you just need to train your developers accordingly.
- treflop 2y agoI've always felt the the rebase vs. merge debate was pointless because I never have dirty internal history by the time that I'm ready to make an MR/PR. It's just that squashing takes 2 seconds. I just shift-select the commits in my Git client and click 'squash'. To me it's just like cleaning up after cooking. And if I want to re-order my commits, I just like drag and drop the order of them. If I told you right now to squash or re-order your last 5 commits and you think it'd take you longer than 2 seconds, you are honestly using a bad tool. Yet hundreds of people have spent many human hours writing these long blog posts about how you have to do things a certain way yadda yadda yadda when the real problem is that they use bad tools, squashing is such a pain, they don't bother to clean up their "fix 1" "fix 2" "try again" commits, and everyone has to deal with Git gymnastics at the end.