9 ms·
Git Rebase for the Terrified
- coffeebeqn 9mo agoI wish rebase was taught as the default - I blame the older inferior version control software. It’s honestly easier to reason about a rebase than a merge since it’s so linear. Understanding of local versus origin branch is also missing or mystical to a lot of people and it’s what gives you confidence to mess around and find things out
- Akranazon 9mo agoThe end result of a git rebase is arguably superior. However, I don't do it, because the process of running git rebase is a complete hassle. git merge is one-shot, whereas git rebase replays commits one-by-one. Replaying commits one-by-one is like a history quiz. It forces me to remember what was going on a week ago when I did commit #23 out of 45. I'm grateful that git stores that history for me when I need it, but I don't want it to force me to interact with the history. I've long since expelled it from my brain, so that I can focus on the current state of the codebase. "5 commits ago, did you mean to do that, or can we take this other change?" I don't care, I don't want to think about it. Of course, this issue can be reduced by the "squash first, then rebase" approach. Or judicious use of "git commit --amend --no-edit" to reduce the number of commits in my branch, therefore making the rebase less of a hassle. That's fine. But what if I didn't do that? I don't want my tools to judge me for my workflow. A user-friendly tool should non-judgmentally accommodate whatever convenient workflow I adopted in the past. Git says, "oops, you screwed up by creating 50 lazy commits, now you need to put in 20 minutes figuring out how to cleverly combine them into 3 commits, before you can pull from main!" then I'm going to respond, "screw you, I will do the next-best easier alternative". I don't have time for the judgement.
- deleted 9mo ago[deleted]
- teaearlgraycold 9mo agoThis seems crazy to me as a self-admitted addict of “git commit --amend --no-edit && git push --force-with-lease”. I don’t think the tool is judgmental. It’s finicky. It requires more from its user than most tools do. Including bending over to make your workflow compliant with its needs.
- theryan 9mo agoWhile it is a bit of a pain, it can be made a lot easier with the --keep-base option. This article is a great example https://adamj.eu/tech/2022/03/25/how-to-squash-and-rebase-a-git-branch/ https://adamj.eu/tech/2022/03/25/how-to-squash-and-rebase-a-... of how to make rebasing with merge conflicts significantly easier. Like you said though, it's not super user-friendly but at least there are options out there.
- nicoburns 9mo ago> "oops, you screwed up by creating 50 lazy commits, now you need to put in 20 minutes figuring out how to cleverly combine them into 3 commits, before you can pull from main!" You can also just squash them into 1, which will always work with no effort.
- DHRicoF 9mo agoThen is not rebase your problem, but all your other practices. Long lived feature branches with lot's of unorganized commits with low cohesion. Sometimes it's ok to work like this, but you asking git not being judgamental is like saying your roomba should accomodate to you didin't asking you to empty it's dust bag.
- PaulDavisThe1st 9mo agoYou can make long lived feature branches work with rebase, you just have to regularly rebase along the way. I had a branch that lived for more than a year, ended up with 800+ commits on it. I rebased along the way, and the predictably the final merge was smooth and easy.
- layer8 9mo agoI don’t see how rebase frequency changes the problem of getting conflicts with some random commit within your long-lived branch, when doing a rebase. I rebase often myself, but I don’t understand the logic here.
- PaulDavisThe1st 9mo ago1) because git rerere remembers the resolutions to the .. 2) small conflicts when rebasing the long lived branch on the main branch if instead I delayed any rebasing until the long lived branch was done, I'd have no idea of the scale of the conflicts, and the task could be very, very different. Granted, in some cases there would be no or very few conflicts, and then both approaches (long-lived branch with or without rebases along the way) would be similar.
- layer8 9mo agoIf you do a single rebase at the end, there is nothing to remember, you just get the same accumulated conflicts you also collectively get with frequent rebases. Hence I don’t understand the benefit of the latter in terms of avoiding conflicts.
- just6979 9mo agoA merge can have you doing a history quiz as well. Conflicts can occur in merges just as easily as rebases. Trouble with trying to resolve conflicts after a big merge is that now you have to keep the entire history in your head, because you don't have the context of which commit the change happened in. With rebase you'd be right there in the flow of commits when resolving conflicts.
- Groxx 9mo ago>Replaying commits one-by-one is like a history quiz. It forces me to remember what was going on a week ago when I did commit #23 out of 45. While I agree this is a rather severe downside of rebase... if you structure your commits into isolated goals, this can actually be a very good thing. Which is (unsurprisingly) what many rebasers recommend doing - make your history describe your changes as the story you want to tell, not how you actually got there. You don't have to remember commit #23 out of 45 if your commit is "renamed X to Y and updated callers" - it's in the commit message. And your conflict set now only contains things that you have to rename, not all renames and reorders and value changes everything else that might happen to be nearby. Rebase conflicts can sometimes be significantly smaller and clearer than merge conflicts, though you have to deal with multiple instead of just one.
- echelon 9mo agogit rebase squash as a single commit on a single main branch is the one true way. I know a lot of people want to maintain the history of each PR, but you won't need it in your VCS. You should always be able to roll back main to a real state. Having incremental commits between two working stages creates more confusion during incidents. If you need to consult the work history of transient commits, that can live in your code review software with all the other metadata (such as review comments and diagrams/figures) that never make it into source control.
- jameshush 9mo agoThis is one of the few hills I will die on. After working on a team that used Phabricator for a few years and going back to GitHub when I joined a new company, it really does make life so much nicer to just rebase -> squash -> commit a single PR to `main`
- fc417fc802 9mo agoWhat was stopping you from squash -> merge -> push two new changesets to `main`? Isn't your objection actually to the specifics of the workflow that was mandated by your employer as opposed to anything inherent to merge itself?
- hnarn 9mo agoI completely agree. It also forces better commit messages, because "maintaining the history of each PR" is forced into prose written by the person responsible for the code instead of hand-waving it away into "just check the commits" -- no thanks.
- _flux 9mo agoMerging merge requests as merge commits (rather than fast-forwarding them) gives the same granularity in the main branch, while preserving the option to have bisect dive inside the original MR to actually find the change that made the interesting change in behavior.
- 9mo ago
- jillesvangurp 9mo agoRebase your local history, merge collaborative work. It helps to just relabel rebase as "rewrite history". That makes it more clear that it's generally not acceptable to force push your rewritten history upstream. I've seen people trying to force push their changes and overwrite the remote history. If you need to force push, you probably messed up. Maybe OK on your own pull request branches assuming nobody else is working on them. But otherwise a bad idea. I tend to rebase my unpushed local changes on top of upstream changes. That's why rebase exists. So you can rewrite your changes on top of upstream changes and keep life simple for consumers of your changes when they get merged. It's a courtesy to them. When merging upstream changes gets complicated (lots of conflicts), falling back to merging gives you more flexibility to fix things. The resulting pull requests might get a bit ugly if you merge a lot. One solution is squash merging when you finally merge your pull request. This has as the downside that you lose a lot of history and context. The other solution is to just accept that not all change is linear and that there's nothing wrong with merging. I tend to bias to that. If your changes are substantial, conflict resolution caused by your changes tends to be a lot easier for others if they get lots of small commits, a few of which may conflict, rather than one enormous one that has lots of conflicts. That's a good reason to avoid squash merges. Interactive rebasing is something I find too tedious to bother with usually. But some people really like those. But that can be a good middle ground. It's not that one is better than the other. It's really about how you collaborate with others. These tools exist because in large OSS projects, like Linux, where they have to deal with a lot of contributions, they want to give contributors the tools they need to provide very clean, easy to merge contributions. That includes things like rewriting history for clarity and ensuring the history is nice and linear.
- cousin_it 9mo agoMaybe I'm old, but I still think a repository should be a repository: sitting on a server somewhere, receiving clean commits with well written messages, running CI. And a local copy should be a local copy: sitting on my machine, allowing me to make changes willy-nilly, and then clean them up for review and commit. That's just a different set of operations. There's no reason a local copy should have the exact same implementation as a repository, git made a wrong turn in this, let's just admit it.
- tjpnz 9mo agoI've had recent interns who've struggled with rebase and they've never known anything but Git. Never understood why that was given they seem ok with basic commits and branching. I would agree that rebase is easier to reason about than merging yet I'm still needing to give what feels like a class on it.
- recursive 9mo agoThe fact that people have a harder time understanding rebase is evidence that rebase is harder to reason about. Whether you update your understanding based on that evidence is up to you. If I have to pick between merge and rebase, I would generally pick merge. It seems to cause less conflicts with long-lived branches. Commits maintain their identity so each one has to be conflict-resolved at most once. However, even better for me (and my team) is squash on PR resolve.
- jghn 9mo agoIMO it's one of those things where rebase is at first less intuitive but once you get it is a lot simpler & easier to reason about. In contrast merging at first seems more straightforward but is actually less so. that's not a value judgement in either direction, both initially simpler and longterm simpler have their merits.
- CJefferson 9mo agoI don't mind rebasing a single commit, but I hate it when people rebase a list of commits, because that makes commits which never existed before, have probably never been tested, and generally never will be. I've had failures while git bisecting, hitting commits that clearly never compiled, because I'm probably the first person to ever check them out.
- Marsymars 9mo agoSometimes it feels like the least-bad alternative. e.g. I'm currently working on a substantial framework upgrade to a project - I've pulled every dependency/blocker out that could be done on its own and made separate PRs for them, but I'm still left with a number of logically independent commits that by their nature will not compile on their own. I could squash e.g. "Update core framework", "Fix for new syntax rules" and "Update to async methods without locking", but I don't know that reviewers and future code readers are better served by that.
- wonger_ 9mo agoI wonder how relevant and feasible this workflow would be: https://graydon2.dreamwidth.org/1597.html https://graydon2.dreamwidth.org/1597.html Where you have two repositories, one "polished" where every commit always passes, and another for messier dev history.
- chuckadams 9mo agoIt seems to me the "Not Rocket Science" invariant is upheld if you just require all PRs to be fast-forward changes. Which I guess is an argument in support of rebase, but a clean merge counts too. If the test suite passes on the PR branch, it'll pass on main, because that's what main will be afterward. Ideally you don't even test the same commit hash twice. If you have expensive e2e tests, then you might want to keep a 'latest' tag on main that's only updated when those pass.
- capitainenemo 9mo agoIn mercurial you could have those in phase hidden for future reference. In jujutsu you can have those in a local set, but not push upstream. Only unfortunate thing with jujutsu is because it is trying to be a git overlay, you lose state that a mercurial clone on another machine would have.
- eeperson 9mo agoI've heard people say before that it is easier to reason about a linear history, but I can't a think of a situation where this would let me solve a problem easier. All I can think of is a lot of downsides. Can you give an example where it helps?
- jayd16 9mo agoIf this was the main strategy used even for public/shared branches, then everyone would have to deal with changing, conflicting histories all the time.
- astrobe_ 9mo agoOh, that's why. I barely used any CVS before Git, so I was always puzzled about the "weird" opinions on this topic. I'm still puzzled by the fact that some people seem to reject entirely the idea of rewriting history - even locally before you have pushed/published it anywhere. Sometimes people look sort of "superstitious" to me about Git. I believe this is caused by learning Git through web front-ends such as Github, GitLab, Gitea etc., that don't tell you the entire truth; desktop GUI clients also let the users only see Git through their own, more-or-less narrow "window". TBH, sometimes Git can behave in ways you don't expect, like seeing conflicts when you thought there wouldn't be (but up to now never things like choosing the "wrong" version when doing merges, something I did fear when I started using it a ~decade ago). However one usually finds an explanation after the fact. Something I've learned is that Git is usually right, and forcing it to do things is a good recipe to mess things up badly.
- bodge5000 9mo agoFunnily enough in all my years of using git, this thread is the first time I've encountered merge. It sounds easier I suppose, but I don't really have a problem with rebase and will likely just continue as is
- thibaut_barrere 9mo agoPSA: I’m not terrified of rebase, yet it’s good to know this: https://docs.github.com/en/get-started/using-git/about-git-rebase https://docs.github.com/en/get-started/using-git/about-git-r... > Warning - Because changing your commit history can make things difficult for everyone else using the repository, it's considered bad practice to rebase commits when you've already pushed to a repository. A similar warning is in Atlassian docs.
- ongy 9mo agoI think a large part of this is about how a branch is expected to be used. Branches that people are expected to track (i.e. pull from or merge into their regularly) should never rebase/force-push. Branches that are short-lived or only exist to represent some state can do so quite often.
- thibaut_barrere 9mo agoIt is this, plus more: - the web tooling must react properly to this (as GH does mostly) - comments done at the commit level are complicated to track - and given the reach of tools like GH, people shooting their own foot with this is (even experienced ones) most likely generate a decent level of support for these tools teams
- xlii 9mo agoAlso branches that are write-only by a single person by consensus. E.g. "personal" PR branches that are not supposed to be modified by anyone but owner.
- mr_mitm 9mo agoIs there a reason why that recommendation cannot be changed to "don't ever force push unless you are certain no one else has fetched this branch"?
- z3dd 9mo agoWell that's a distinction which makes sense in theory but is not realistic in practice for most projects with multiple contributors.
- xlii 9mo agoAllow me (today) to be that person to propose checking out Jujutsu instead [0]. Not only it has a superpower of atomic commits (reviewers will love you, peers will hate 8 small PRs that are chained together ;-)) but it's also more consistent than git and works perfectly well as a drop-in replacement. In fact, I've been using Jujutsu for ~2 years as a drop-in and nobody complained (outside of the 8 small PRs chained together). Git is great as a backend, but Jujutsu shines as a frontend. [0]: https://www.jj-vcs.dev/latest/ https://www.jj-vcs.dev/latest/
- vlovich123 9mo agoHow do you handle publishing the stack?
- dcre 9mo agoThere’s tooling like https://github.com/LucioFranco/jj-spr https://github.com/LucioFranco/jj-spr for managing stacks of PRs, but for stacks of 2 or 3 it’s not too bad to do it manually.
- vlovich123 9mo agoI’ve not had any luck with that tool in terms of creating meaningfully reviewable prs. I’m hoping I can maybe leverage graphite for the stack generation while authoring everything in jj. We’ll see how that goes
- wocram 9mo agoIt depends on what you're publishing to, but works with most other tools by using a bookmark for each publish target.
- _flux 9mo agoI think I'd love to use Jujutsu, but I enjoy Magit (for Emacs) too much to entertain the thought of switching :/. Besides, Magit rebasing is also pretty sweet.
- 9mo ago
- ngruhn 9mo agoMaintaining linear history is arguably more work. But excessively non-linear history can be so confusing to reason over. Linear history is like reality: One past and many potential futures. With non-linear history, your past depends on "where you are". ----- M -----+--- P / ----- D ---+ Say I'm at commit P (for present). I got married at commit M and got a dog at commit D. So I got married first and got a Dog later, right? But if I go back in time to commit D where I got the dog, our marriage is not in my past anymore?! Now my wife is sneezing all the time. Maybe she has a dog allergy. I go back in time to commit D but can't reproduce the issue. Guess the dog can't be the problem.
- hnarn 9mo ago> So I got married first and got a Dog later, right? No. In one reality, you got married with no dog, and in another reality you got a dog and didn't marry. Then you merged those two realities into P. Going "back in time to commit D" is already incorrect phrasing, because you're implying linear history where one does not exist. It's more like you're switching to an alternate past.
- ngruhn 9mo agoThe point is that it's harder to reason over.
- hnarn 9mo agoI don't really agree that it's harder to reason over in the sense that it's hard to understand the consequences, but I also agree that a linear history is superior for troubleshooting, just like another comment pointed out that single squashed commits onto a main branch makes it easier to troubleshoot because you go from a working state to a non-working state between two commits.
- agumonkey 9mo agothere are others tricky time issues with staging/prod parallel branching models too, the most recent merge (to prod) contains older content, so time slips .. maybe for most people it's obvious but it caused me confusion a few times to compare various docker images
- embedding-shape 9mo ago> The response is often hesitation or outright fear. I get it. Rebase has a reputation for destroying work, and the warnings you see online don’t help. The best method for stop being terrified of destructive operations in git when I first learned it, was literally "cp -r $original-repo $new-test-repo && go-to-town". Don't know what will happen when you run `git checkout -- $file` or whatever? Copy the entire directory, run the command, look at what happens, then decide if you want to run that in your "real" repository. Sound stupid maybe, but if it works, it works. Been using git for something like a decade now, and I'm no longer afraid of destructive git operations :)
- psychoslave 9mo agoOne step further which is in-scope-of-the-tool spirit will be git clone locally your repository. And still one step further, just create a new branch to deal with the rebase/merge. Yes there are may UX pain points in using git, but it also has the great benefits of extremely cheap and fast branching to experiment.
- afiori 9mo agoin my experience some of the trickiest situations are around gitignore file updates, crlf conversion, case [in]sentivity, etc. where clones and branches are less useful as a testing ground.
- embedding-shape 9mo agoYeah, works for normal "lets try out what happens when I do this" but it can get messy, depending on what you're trying out. That's why I always recommended beginners to literally "cp -r" the entire directory instead, together with the git repository, so they can feel freer to completely experiment and not be afraid of loosing anything. I guess it's actually more of a mental "divider" than anything, it tends to relax people more when they can literally see that their old stuff is still there, and I think git branches can "scare" people in that way. Granted, this is about people very new to git, not people who understands what is/isn't destructive, and just because a file isn't on disk doesn't mean git doesn't know exactly what it is.
- ratchetclank 9mo agoI never understood why rebase is such a staple in the git world. For me "loosing" historical data, like on which branch my work was done is a real issue. In the same class, for commit to not have on which branch they were created as a metadata is a rel painpoint. It always a mess to find what commit were done for what global feature/bugfix in a global gitflow process... I'll probably be looking into adding an commit auto suffix message with the current branch in the text, but it will only work for me, not any contributors...
- chungy 9mo agoSounds like you'd be a fan of Fossil (https://fossil-scm.org https://fossil-scm.org). See for instance: https://fossil-scm.org/home/doc/trunk/www/fossil-v-git.wiki#history https://fossil-scm.org/home/doc/trunk/www/fossil-v-git.wiki#...
- smartmic 9mo agoLet me expand on this with a link to the article "Rebase Considered Harmful" [0]. I also prefer Fossil to Git whenever possible, especially for small or personal projects. [0] https://fossil-scm.org/home/doc/trunk/www/rebaseharm.md https://fossil-scm.org/home/doc/trunk/www/rebaseharm.md
- fc417fc802 9mo ago> Surely a better approach is to record the complete ancestry of every check-in but then fix the tool to show a "clean" history in those instances where a simplified display is desirable and edifying From your link. The actual issue that people ought to be discussing in this comment section imo.
- sigseg1v 9mo agoTHIS is the hill I will die on. Why do we advocate destroying information/data about the dev process when in reality we need to solve a UI/display issue? The amount of times in the last 15ish years I've solved something by looking back at the history and piecing together what happened (eg. refactor from A to B as part of a PR, then tweak B to eventually become C before getting it merged, but where there are important details that only resulted because of B, and you don't realize they are important until 2 years later) is high enough that I consider it very poor practice to remove the intermediate commits that actually track the software development process.
- rich_sasha 9mo agoI have lost ~irretrievably work via rebase. I was working on a local branch, periodically rebasing it to master. All was well, my git history was beautiful etc. Then down the line I realised something was off. Code that should have been there wasn't. In the end I concluded some automatic commit application while rebasing gobbled up my branch changes. Or frankly, I don't even entirely know what happened (this is my best guess), all I know is, suddenly it wasn't there. No big deal, right? It's VCS. Just go back in time and get a snapshot of what the repo looked like 2 weeks ago. Ah. Except rebase. I like a clean linear history as much as the next guy, but in the end I concluded that the only real value of a git repo is telling the truth and keeping the full history of WTF really happened. You could say I was holding it wrong, that if you just follow this one weird old trick doctor hate, rebase is fine. Maybe. But not rebasing and having a few more squiggles in my git history is a small price to pay for the peace of mind that my code change history is really, really all there. Nowadays, if something leaves me with a chance that I cannot recreate the repo history at any point in time, I don't bother. Squash commits and keeping the branch around forever are OK in my book, for example. And I always commit with --no-ff. If a commit was never on master, it shouldn't show up in it.
- nh2 9mo ago> Just go back in time and get a snapshot of what the repo looked like 2 weeks ago. Ah. Except rebase. This is false. Any googling of "git undo rebase" will immediately point out that the git reflog stores all rebase history for convenient undoing. Shockingly, got being a VCS has version control for the... versions of things you create in it, not matter if via merge or rebase or cherry-pick or whatever. You can of course undo all of that.
- rich_sasha 9mo agoUp to a point - they are garbage collected, right? And anyway, I don't want to dig this deep in git internals. I just want my true history. Another way of looking at it is that given real history, you can always represent it more cleanly. But without it you can never really piece together what happened.
- pabs3 9mo agogit rebase conflict resolution is a lot less scary with the zdiff3 merge.conflictStyle option. Also incremental rebasing with mergify/git-imerge/git-mergify-rebase/etc is really helpful for long-lived branches that aren't merged upstream. https://github.com/brooksdavis/mergify https://github.com/brooksdavis/mergify https://github.com/mhagger/git-imerge https://github.com/mhagger/git-imerge https://github.com/CTSRD-CHERI/git-mergify-rebase https://github.com/CTSRD-CHERI/git-mergify-rebase https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297 https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee650... I also love git-absorb for automatic fixups of a commit stack. https://github.com/tummychow/git-absorb https://github.com/tummychow/git-absorb
- eddyg 9mo agoSo many people don’t know about git-absorb! It’s fantastic.
- 708145_ 9mo agoI see no need to ever rebase manually, just merge on your branch and always fast-forward squash merge (only sane default) with GitHub/GitLab/whatever.
- 708145_ 9mo ago_squash merge_ to main ofc.
- DarkNova6 9mo agoI don't see how this is not the first answer. What tools does everybody else work with??
- OkayPhysicist 9mo agoSquash merges are a hacky solution to the git bisect problem that was solved correctly by --first-parent 20 years ago. There are fully employed software developers working on important stuff that literally were never alive in a world where squash merges were needed. Don't erase history. Branch to a feature branch, develop in as many commits as you need, then merge to main, always creating a merge commit. Oftentimes, those commit messages that you're erasing with a squash are the most useful documentation in the entire project.
- quacker 9mo agoUsing git history as documentation is hacky. A majority of feature branch commit messages aren't useful ("fix test case X", "fix typo", etc), especially when you are accepting external contributions. IF I wanted to use git history as a form of documentation (I don't. I want real documentation pages), I'd want the history curated into meaningful commits with descriptive commit messages, and squash merging is a great way to achieve that. Git bisect is not the only thing I do with git history after all. And if I'm using GitHub/Gitlab, I have pull requests that I can look back on which basically retain everything I want from a feature branch and more (like peer review discussion, links to passing CI tests, etc). Using the Github squash merge approach, every commit in the main branch refers back to a pull request, which makes this super nice.
- tomaytotomato 9mo agoGithub is not Git but I find the Squash and Merge functionality on Github's Pull Request system means I no longer need to worry about rebasing or squashing my commits locally before rebasing. At work though it is still encouraged to rebase, and I have sometimes forgotten to squash and then had to abort, or just suck it up and resolve conflicts from my many local commits.
- cdmckay 9mo agoThis Rebase only makes sense if you making huge PRs where you need to break it down into smaller commits to have them make sense. If you keep your PRs small, squashing it works well enough, and is far less work and more consistent in teams. Expecting your team to carefully group their commits and have good commit messages for each is a lot of unnecessary extra work.
- ivanjermakov 9mo agoSquash is not Github specific and is part of git: git merge --squash
- quacker 9mo agoRight, but they are referring to configuration on a GitHub repository that can make squash merge automatic for all pull request merges. e.g. When clicking the big green "Merge pull request" button, it will automatically squash and merge the PR branch in. So then I don't need to remind or wait for contributors to do a squash merge before merging in their changes. (Or worse, forget to squash merge and then I need to fix up main).
- freeplay 9mo agoCouldn't agree more. Squash merges to main ONLY. That way, I don't care if your branch contains 100 commits or 1 commit. I don't need to worry about commit messages like: - fix 1 - fix 2 - dfljfdlkfdj - does it work now? Do whatever you want with your commits on your feature branch. Just make sure the title of your PR is clean and follows our formatting. Git history is always well formatted and linear. It's the ideal solution.
- dominicrose 9mo agoWhen things get messy I use Sublime Merge with two tabs, one with the code that's open in VS Code and one with the same project but different branch/commit. It works well on Linux. I've managed to make it work with Windows + WSL but I don't recommend it.
- flux3125 9mo ago>the worst case scenario for a rebase gone wrong is that you delete your local clone and start over. Wouldn't it be enough to simply back up the branch (eg, git checkout -b current-branch-backup)? Or is there still a way to mess up the backup as well?
- aurecchia 9mo agoYeah, deleting your local clone and starting over should normally not be necessary, unless you really mess things up badly. The "local backup branch" is not really needed either because you can still reference `origin/your-branch` even after you messed up a rebase of `your-branch` locally. Even if you force-pushed and overwrote `origin/your-branch` it's most likely still possible to get back to the original state of things using `git reflog`.
- OkayPhysicist 9mo agoFor amateurs at Git, recovery branches/tags are probably easier to switch back to than digging through reflog. Particularly if you're interacting with Git via some GUI that hides reflog away as some advanced feature.
- aeinbu 9mo ago> I always use VS Code for this step. Its merge conflict UI is the clearest I’ve found: it shows “Accept Current Change,” “Accept Incoming Change,” “Accept Both Changes,” and “Compare Changes” buttons right above each conflict. I still get confused by vscode’s changing the terms used by Git. «Current» vs «incoming» are not clear, and can be understood to mean two different things. - Is “current” what is on the branch I am rebasing on? Or is it my code? (It’s my code) - Is “incoming” the code I’m adding to the repo? Or is it what i am rebasing on to? (Again, the latter is correct) I find that many tools are trying to make Git easier to understand, but changing the terms is not so helpful. Since different tools seldom change to the same words, it just clutters any attempts to search for coherent information.
- afiori 9mo agoFor merges current is the branch you are on, for rebases it helps to see them as a serie of cherry picks, so current would be the branch you would be on while doing the cherry pick equivalent to this step of the rebase.
- spiffyk 9mo agoGit's "ours"/"theirs" terminology is often confusing to newcomers, especially when from a certain (incorrect, but fairly common) point of view their meaning may appear to be swapped between merge and rebase. I think in an attempt to make the terminology less confusing UIs tend to reinvent it, but they always fail miserably, ending up with the same problem, just with slightly different words. This constant reinvention makes the situation even worse, because now the terminology is not only confusing, but also inconsistent across different tools.
- Izkata 9mo agoI think even presenting them as options makes it even more confusing to newcomers. Usually I find that neither is correct and there's a change on both sides I need to manually merge (so I don't even pay attention to the terminology), but I've seen co-workers just blindly choose their changes because it's familiar looking then get confused when it doesn't work right.
- 9mo ago
- Deadron 9mo agoJust do a normal merge, then squash all your commits in into one, using rebase, then a rebase onto a branch is easy.
- game_the0ry 9mo agoI have been contributing code for 10+ years, and I have worked on teams that did rebase and others that did not. 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.
- nicoburns 9mo agoThe main benefit I've found is when there is work happening concurrently in multiple feature branches at once (e.g. by different people). Rebase-merging greatly simplifies dealing with merge conflicts as you only have a simple diff against a single branch to deal with. The more work you have in progress at once the more important this becomes.
- skipkey 9mo agoI can give you an example of when I am glad I rebased. There have been many times I have been working on a feature that was going to take some time to finish. In that case my general workflow is to rebase against main every day or two. It lets me keep track of changes and handle conflicts early and makes the eventual merge much simpler. As for debugging I’ve never personally had to do this, but I imagine git bisect would probably work better with rebased, squashed commits.
- hnben 9mo ago> I can give you an example of when I am glad I rebased I think the question was about situations where you were glad to rebase, when you could have merged instead
- alemanek 9mo agoThey kind of spoke to it. Rebasing to bring in changes from main to a feature branch which is a bit longer running keeps all your changes together. 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
- MeteorMarc 9mo agoNice, git rerere would have saved me in the past.
- g-b-r 9mo agoIt's so weird that it's not enabled by default, although occasionally it can lead to surprising problems (when it records wrong resolutions). I had it enabled for years, and the time when I tried turning it off the rebasing esperience was a hundred times worst.
- Myrmornis 9mo ago> the worst case scenario for a rebase gone wrong is that you delete your local clone and start over. That’s it. Your remote fork still exists. This is absolute nonsense. You commit your work, and make a "backup" branch pointing at the same commit as your branch. The worst case is you reset back to your backup.
- dcre 9mo agoIn about 12 years of using git (jj user now) I almost never rebased through the CLI, but I found shuffling branches around in a GUI pretty intuitive. I liked GitUp[0], which gave me undo way before jj existed. The common view that a Git GUI is a crutch is very wrong, even pernicious. To me it is the CLI that is a disruptive mediation, whereas in a GUI you can see and manipulate the DAG directly. Obligatory jj plug: before jj, I would have agreed with the top comment[1] that rebasing was mostly unnecessary, even though I was doing it in GitUp pretty frequently — I didn't think of it as rebasing because it was so natural. Now that I use jj I see that the cost-benefit analysis around git rebase is dominated by the fact that both rebasing and conflict resolution in git are a pain in the ass, which means the benefit has to be very high to compensate. In jj they cost much less, so the neatness benefit can be quite small and still be worth it. Add on the fact that Claude Code can handle it all for you and the cost is down to zero. [0]: https://gitup.co/ https://gitup.co/ [1]: https://news.ycombinator.com/item?id=46602056 https://news.ycombinator.com/item?id=46602056
- jonfw 9mo agoCoding agents are excellent at solving merge and rebase conflicts according to natural language instruction.
- 6LLvveMx2koXfwn 9mo agowas fully expecting: mv folder folder-old git clone git@github/folder
- phrotoma 9mo agogit rebase appears to be a random number generator to me. I've got two PRs in flight, I realize that one branch requires something I did in the other branch. I go merge branch one, then rebase branch two off main. Half the time; success, get on with my day. The other half of the time; anarchy, madness, dogs and cats living together. I remain terrified.
- skeptrune 9mo agoi hope ai agents read this
- jimbobimbo 9mo agoRebase is easy and not terrifying. Here's a 1k word article on how to do it correctly. Or just do a merge and move on with your life.
- bheadmaster 9mo agoIf you want to have a linear history on main, either always rebase your branch onto main, or merge but only accept squashed commits onto main.
- WolfeReader 9mo agoI would prefer to have accurate history over linear "history".
- bheadmaster 9mo agoGood luck bisecting.
- WolfeReader 9mo agoWith --first-parent, I don't need good luck in my bisecting.
- mathisfun123 9mo ago> Here's a 1k word article lol if 1k words is "not easy" for you, i think you have bigger problems than merge vs rebase.
- darknavi 9mo agoIt's funny because I learned git on the job and we exclusively used rebase when I was learning my git fundamentals. I wouldn't say merging scares be, but it's never a tool a reach for.
- DHRicoF 9mo agoI don't understand why I would push to origin my local branch. This will (potentially) require multiple push -f. I prefer to share the work in a state I considere complete. As an alternative, just create a new branch! `git branch savepoint-pre-rebase`. That's all. This is extremely cheap (just copy a reference to a commit) and you are free to play all you want. You are a little more paranoid? `git switch -c test-rebase` and work over the new branch.
- throwaway7783 9mo agoI avoid rebase like plague (perhaps because of my early experiences with it). I used to get continuous conflicts for the same commits again and again, and the store and replay kinda helped with it but not always. Merge always worked for me (once I resolve conflicts, thats the end of it). Now I always merge main into my feature branch and then merge it back to main when ready. Does it pollute the history? Maybe, but Ive never looked. It does not matter to our team.
- literallyroy 9mo agoI think the callout to squash first will be helpful (if your lots of commits aren’t good info themselves)
- throwaway7783 9mo agoPerhaps. But you can see the DX of rebase is abysmal compared to merge. squash, rerere, force push, remember to push to remote before rebase, more coordination if multiple people are working on feature branch etc. I still prefer merge. Its simple and gets out of my way as long as I dont care about purity of history
- leptons 9mo agoSame here. I lead a team and I really don't care about keeping the git history "clean". It is what it is. Squashing commits wouldn't help me at all since the history rarely ever factors into our workflow. Rebase and other fancy Git things have caused problems in the past so I avoid getting too complex with Git. I'm not a Git engineer, I'm a software engineer. Merging has always just worked, and I know exactly what to expect. If there's a big hairy branch that I need to merge, and I know there will be conflicts, I create a branch from Main, merge the hairy branch into it, and see what happens. Fix the issues there, and then merge that branch to Main when everything is working. Merge is simple, and I don't have to be master of Git to get things done.
- sesuximo 9mo agoTIL ppl are afraid of rebase lmao
- quacker 9mo agoRebasing replays your commits on top of the current main branch, as if you’d just created your branch today. The result is a clean, linear history that’s easier to review and bisect when tracking down bugs. The article discusses why contributors should rebase their feature branches (pull request). The reason they give is for clean git history on main. The more important reason is ensure the PR branch actually works if merged into current main. If I add my change onto main, does it then build, pass all tests, etc? What if my PR branch is old, and new commits have been added onto main that I don't have in my PR branch? Then I can merge and break main. That's why you need to update your PR branch to include the newer commits from main (and the "update" could be a rebase or a merge from main or possibly something else). The downside of requiring contributors to rebase their PR branch is (1) people are confused about rebase and (2) if your repository has many contributors and frequent merges into main, then contributors will need to frequently rebase their PR branch, and each rebase their PR checks need to re-run, which can be time consuming. My preference with Github is to squash merge into main[1] to keep clean git history on main. And to use merge queue[2], which effectively creates a temp branch of main+PR, runs your CI checks, and then the PR merge succeeds into main only if checks pass on the temp branch. This approach keeps super clean history on main, where every commit includes a specific PR number, and more importantly minimizes friction for contributors by reducing frequent PR rebases on large/busy repos. And it ensures main is never broken (as far as your CI checks can catch issues). There's also basically no downside for very small repos either. 1. https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/about-merge-methods-on-github#squashing-your-merge-commits https://docs.github.com/en/repositories/configuring-branches... 2. https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue#about-merge-queues https://docs.github.com/en/repositories/configuring-branches...
- g0xA52A2A 9mo ago> Before rebasing, push your current work to your remote fork. This gives you a backup you can recover from if anything goes wrong I don't follow this. Just abort the rebase?
- globular-toast 9mo ago> Rebase has a reputation for destroying work, and the warnings you see online don’t help. Everyone using git needs to accept the following. Say it out aloud if you have to: no command in git can ever modify or delete a commit. After a botched rebase your old work is one simple reset away using the reflog. Then you can have another go or reach out for help.
- g-b-r 9mo agoIt's dangerous to think that nothing can ever happen to your repository, corruptions or weird states you don't know how to recover from are not even rare. So do take backups, of the whole local repository. At the beginning of using git I used to keep dozens of copies around, if the repository is not huge it's trivial (and compressed they typically don't take up much more space than a single copy). That saved my ass several times
- globular-toast 9mo agoOf course you should keep backups. But that's a different abstraction level. I have never in 15+ years of using git daily encountered one of these "weird states". Because, like I said, no command in git can modify or delete a commit. The only real mistake you can make is hard reset with uncommitted changes in your working dir. Other than that it's down to git bugs, which I have never encountered.
- g-b-r 9mo agohttps://stackoverflow.com/questions/66449211/a-lock-file-already-exists-in-the-repository-which-blocks-this-operation-from-c https://stackoverflow.com/questions/66449211/a-lock-file-alr... happens fairly easily, and at least years ago it was not easy to figure out how to solve it. I think I did run in other bugs that did appear to have messed up the repository. > like I said, no command in git can modify or delete a commit. Well, you can end up losing commits by playing with the reflogs or deleting branches (if you haven't checked out the branch in the last by default 30 days, its commits might get deleted quickly)
- aib 9mo agoMy default pull is ff-only. I don't like merging or rebasing by default. When working in a short-lived branch, I like to rebase. I usually get no or simply easy-to-solve conflicts. I like my small and numerous commits stacked on top of the current develop. Regardless or whether we squash or not. For long-lived branches (and technically for hard merges, though I've been using rerere more and more) merge is a better option. What kills bisect, IMO, is large commits or commits with multiple subjects/goals. That's the reason I don't like squashed PRs.
- golemiprague 9mo ago[dead]
- jdthedisciple 9mo agoWhy would you rebase onto master locally in a team environment? The way to do this are pull requests on the remote.
- parasti 9mo agoBeen using git since 2008, and this looks more intimidating than helpful. git rebase takes a list of patches and applies them one by one on top of a given "base" commit. And that's it. It's not all this complicated git command soup. It's just patches. No objects, no sha1s, no metadata, no branches, just literal textual diffs applied in order. It's the dumbest and also one of the most powerful things about git if you care at all about a readable history. If you don't, that's fine, but in some circles, e.g. most (if not all) open source projects, patch management and history hygiene is a very important part of good collaboration.
- kwar13 9mo agoThat was great. I have run into this issue and had a lot of difficulty rebasing my changes.
- racl101 9mo agoOne thing I still love about blogs like this that AI can never replace is that it takes a topic that might seem complicated to some people such as myself (Git Rebase does actually terrify me) and it talks about it in great detail in a way where I don't have to know what to ask. I don't have to prompt about something I don't even know where to begin. The topic is introduced and elaborated on while speaking to a general audience. So that's why I still like to see tech blogs out there.
- Groxx 9mo agoI also get tons of mileage out of This One Weird Trick: make a new branch first. Every single time it appears non-trivial, just abort and branch before continuing. Then if you screw up, even several steps later when it's hard to un-rebase a portion, you just go back to the original. No need to dig through the ever-confusing reflog format, just use branches. For really gnarly ones, it also means you can early compare the two diffs to see if you missed anything. Once you're fully happy with it, you can push that new one, or just go back to your original and `git reset --hard after-rebase-branch` to adopt the new history.
- tigerlily 9mo agoI do this, and with TortoiseGit I just pick and choose the good bits and put them as atomic changes in their own branches and PRs.
- yowlingcat 9mo agoThis is the way. Branches are structurally cheap in git for a reason - to make it easy to do this! The only minor pain is that then I have to remember to clean up the unused branches for paths that didn't pan out but that isn't so bad anyways and helps me make sense of/remind me of what didn't work as I was trying to solve something.
- Groxx 9mo agobranch-rebase-3-final_2_DO-NOT-EDIT---IN-PROD-incident_93473672 The struggle is real. I generally have a "show branches by age" script to help that a bit
- DenisM 9mo agoI found it a lot safer to cherry pick into a new temp branch, test things out, rename the old branch to an archive name, and rename the new temp branch to old name. That is until I started using graphite, that solved the problem completely for me. The only trick is to never mix graphite and git history editing.
- hambes 9mo agoTo add to the very short "valodating the result" section, let me recommend `git range-diff`. Range diff takes two commit ranges and compares thor commits pairwise, wich is perfect for rebases, since after the rebase all commits still exist and should be mostly identical, just at some other place in the history. Use it like `git range-diff main..origin/mybranch main..mybranch` to compare the local, rebased branch with the upstream branch. This let's you easily verify that eitger mothing changed or that any conflicts were resolved well.
- g-b-r 9mo agoI'm surprised that no one said it, the article's advice of routinely deleting your local repository, without first making a copy, is terrible!!! You lose your whole reflog and all the unreachable commits that way, and so some errors you might make will lead to unrecoverable losses..! If you want do begin from a new clone from time to time, but make copies of the old local repository first, and keep them around! You're bound to lose work occasionally, otherwise. And why even messing around with a remote repository and force pushes, to safeguard yourself from rebase problems you can simply take a local copy of the repository..! That's of course when it's not a huge repository An alternative to keep in mind is to use local clones, updating which will take less time than taking a full copy.
- just6979 9mo ago"Here’s the thing: the worst case scenario for a rebase gone wrong is that you delete your local clone and start over. That’s it. Your remote fork still exists. The main repository still exists." You forgot "your backup local branch still exists". Branching in git is effectively free, just duplicate the one you're worried about rebasing: if the rebase goes wonky enough that you can't cleanly abort it, you just start over on the backup branch, making another duplicate and trying again. It also gives you a nice reference to compare the results of the rebase with your original intentions for the code.
- just6979 9mo agoOh, I guess you kinda did address is, with pushing to your remote fork. But why push? Rebasing a branch doesn't affect any other branches, so a local backup branch is just as safe as a branch on the remote fork. You shouldn't ever need to nuke your clone unless you're trying something silly like rebasing main (without a local backup branch!), or doing more than just rebasing, like messing with the reflog. Also, I don't think it's rebasing that scares people, it's the force push that scares people. There is so much out there saying "never force push or all the trees in a 500 mile radius will spontaneously combust" without explaining the nuances of concurrent work on shared branches vs a personal fork used for making contributions upstream, nor the "safety" of force-with-lease. For the latter (fork for contrib), just yolo it: you're the only one working on your fork!
- mathstuf 9mo agoWhy does it always feel so black-and-white? On our projects we do rebases all the time so that topic history is clean. But we merge into the target branch(es) (our merge bot supports merging to old release branches from a single MR). This gives us: - clean integration branch histories (series of merge commits) - merge commits can contain metadata (topic-level descriptions, trailers for who reviewed, merge request links, test results, etc.) - you can be (pretty) sure that `git bisect --first-parent` will not run into any compilation problems (logical conflicts occur, but are fairly rare; use merge queues to be sure) - none of the "you merged main into your topic" "backwards merges" to deal with too Merging and rebasing each have their pros and cons, so why not use the pros of each and mitigate a lot of the cons at the same time.