I find rebases are only a footgun because the standard git cli is so bad at representing them - things like --force being easier to write than --force-with-lease, there being no way to easily absorb quick fixes into existing commits, interdiffs not really being possible without guesswork, rebases halting the entire workflow if they don't succeed, etc.
I've switched over pretty much entirely to Jujutsu (or JJ), which is an alternative VCS that can use Git as its backend so it's still compatible with Github and other git repos. My colleagues can all use git, and I can use JJ without them noticing or needing to care. JJ has merges, and I still use them when I merge a set of changes into the main branch once I've finished working on it, but it also makes rebases really simple and eliminates most of the footguns. So while I'm working on my branch, I can iteratively make a change, and then squash it into the commit I'm working on. If I refactor something, I can split the refactor out so it's in a separate commit and therefore easiest to review and test. When I get review feedback, I can squash it directly into the relevant commit rather than create a new commit for it, which means git blame tends to be much more accurate and helpful - the commit I see in the git blame readout is always the commit that did the change I'm interested in, rather than maybe the commit that was fixing some minor review details, or the commit that had some typo in it that was fixed in a later commit after review but that relationship isn't clear any more.
And while I'm working on a branch, I still have access to the full history of each commit and how it's changed over time, so I can easily make a change and then undo it, or see how a particular commit has evolved and maybe restore a previous state. It's just that the end result that gets merged doesn't contain all those details once they're no longer relevant.
+1 on this, I also switched to jj when working with any git repo.
What's funny is how much better I understand git now, and despite using jj full time, I have been explaining concepts like rebasing, squashing, and stacked PRs to colleagues who exclusively use git tooling
The magic of the git cli is that it gives you control. Meaning whatever you want to do can be done. But it only gives you the raw tools. You'll need to craft your own workflow on top of that. Everyone's workflow is different.
> So while I'm working on my branch, I can iteratively make a[...]which means git blame tends to be much more accurate and helpful
Everything here I can do easily with Magit with a few keystroke. And magit sits directly on top of git, just with interactivity. Which means if I wanted to I could write a few scripts with fzf (to helps with selection) and they would be quite short.
> And while I'm working on a branch, I still have access to the full history of each commit...
Not sure why I would want the history for a specific commit. But there's the reflog in git which is the ultimate undo tool. My transient workspace is only a few branches (a single one in most cases). And that's the few commits I worry about. Rebase and Revert has always been all I needed to alter them.
I think there's a sense that magit and jj are in some way equivalent tools, although I don't have enough experience with magit to be sure. They both sit in top of git and expose the underlying model of git far more cleanly and efficiently than the standard git cli. The difference is that magit uses interactivity to make git operations clearer, whereas jj tries to expose a cleaner model directly.
That said, there are additional features in jj that I believe aren't possible in magit (such as evolog/interdiffing, or checked-in conflicts), whereas magit-like UIs exist for jj.
You want the history of a specific commit because if you, say, fixup that commit, you want to know how the commit has changed exactly over time. This is especially useful for code review. Let's say you've got a PR containing a refactor commit and a fix commit. You get a review the says you should consider changing the refactor slightly, so you make that change and squash it into the existing refactor commit. You then push the result - how can the reviewer see only the changes you've made to only the refactor commit? That is an interdiff.
In this case, because you've not added any new commits, it's trivial to figure out which commit in the old branch maps to which commit in the new, fixed branch. But this isn't possible in general (consider adding new commits, or reordering something, or updating the commit message somewhere). In jj, each commit also has a change ID, and if multiple commits share the same change ID, then they must be different versions of the same changeset.
You want the history of the repository which includes the history of each commit, because it's a lot easier to type `jj undo` to revert an operation you just did than it is to find the old state of the repository in the reflog and revert to it, including updating all the branch references to point at their original locations. The op log in jj truly is the ultimate undo tool - it contains every state the repository has every been in, including changes to tags and branches that aren't recorded in the reflog, and is much easier to navigate. It is strictly more powerful than the reflog, while being simpler to understand.
> But there's the reflog in git which is the ultimate undo tool.
That one sentence outs you as someone who isn't familiar with JJ.
Here is something to ponder. Despite claims to the contrary, there are many git commands that can destroy work, like `git reset --hard`. The reflog won't save you. However there is literally no JJ command that can't be undone. So no JJ command will destroy your work irretrievably.
I’ve just tested that exact command and the reflog is storing the changes. It’s different from the log command which displays the commit tree for the specified branch. The reflog stores information about operations that updates branches and other references (rebase, reset, amend, commit,…). So I can revert the reset, or a pull.
`git reset --hard` destroys uncommitted changes. There is no git command to recover those files. JJ has a similar command of course, but it saves the files to a hidden commit before changing them.
--force-with-lease is useless if you ever use tools that refresh git status.