37 comments

[ 3.1 ms ] story [ 44.2 ms ] thread
In short, newer versions of git implemented three really frequent use cases of `git rebase --interactive` as separate lower-friction commands. Apparently they only work when there are no conflicts.
> Working with lots of changes in parallel on git can be painful. You end up juggling branches and commits, and running scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze.

I think that only happens when you work on code as text files (i.e character streams) instead of code (i.e structured content with meaning). Like you have commit A and commit B that is in conflict, you should be glad because that's a rough signal that the intent of A and B differs. Your goal should be to think about how to compose A and B so that both intent survives (unless one supersedes the other). Which means you should be at least familiar with A and B.

The issue I found with people that fears conflict is that they often don't understand either A or B (or both). So they are a bad candidate to actually do the operation. It's not a matter of git's cli interface, it's a matter of codebase comprehension and how well you're familiar with the changes in question.

> scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze

`git rebase --abort` exists. One can also set a tag or something before doing the rebase, do whatever, then `git reset --hard $set_tag` to go back. Nothing to be scared of. Not like the prior state is lost.

`git history split` is really going to help me help juniors break up their large PRs into smaller more concise changes. If only it had the option to split an entire branch in two easily.
I like to be like an accountant. No editing history. Create a new "journal entry" (i.e. commit) to fix.
Granted, I have a perspective of a game dev, but this kind of repo defiling just gives me the willies. IMO instead of finding a common ancestor and altering it, just make the desired change upstream and merge it to where it’s needed. If you can’t do that then you have already made a deal with the devil and might reconsider your approach. KISS
> That last part goes further than git rebase --update-refs, which only moves refs sitting inside the range you’re actively rebasing. git history instead finds and rewrites every local branch descended from the commit (while also having an option to limit it to only the current branch).

I'm reading that to mean that when I use `git rebase --update-refs` in this situation, where I've currently checked out `D` and update `B` to `B'`:

  A ──► B ──► C ──► D  
        │              
        └───► E        
I'll end up with this state, where `E` remains untouched?

  A ──► B' ─► C' ─► D'  
  │                   
  └───► B ──► E        
(EDIT: Originally I had `E` point to `B'`, which doesn't make sense)

If I use `git history fixup`, it would also update `E` and end up with this?

  A ──► B' ─► C' ─► D'  
        │              
        └───► E'        
If that's the case, is there a way to get `git rebase` to have the same behavior? I've got decades of `git rebase` burned into my fingers at this point.
I don’t consider myself a coder or programmer, but learning git was like an organizational superpower for my particular brain wiring. I use it for websites, design projects, electronics engineering, music composition, personal knowledge bases, remote administration scripts, config management, snippets, so many applications and so many features for one system. It’s not always perfect, but I tell everyone I work with they should learn it.
I like `git history reword`, would've found that useful in the past (e.g. fixing a bad typo in an older commit).

It sounds like there was probably an equivalent using an existing command but this is easier for me to understand. Thanks for sharing!

I don't get all the effort people spend in perfectly curating git history. No one is ever going back and reading individual commits. Just squash everything before merging and call it a day.
yea i agree, the people who defend perfect git history are most likely not enforcing pull/merge requests. why would I care to look at git history when a pull/merge request is way more informative? they then back it up by saying how rebase is so much better than merge, but yet when you git blame a line of code that was merged and not rebased it's going to indicate the pull/merge request which is going to link back to a requirement. sorry for the harsh comments from these people about you, because imo perfected git history is actually the lazy approach instead of proper change/requirement management
I've been theoretically a big fan of these commands; I use the `jj` equivalents all the time. The roadblock I've run into is that I as far as I can tell (from the man pages and the git source code) there's no way to get `git history` commands to sign commits they modify:

    $ git log --oneline --show-signature  # look ma, I signed my commits!
    3a1dd8f gpg: Signature made Mon 13 Jul 2026 10:45:50 PM CDT
    gpg:                using RSA key FBF32CDBCC134B44FD29B66FA851D929D52FB93F
    gpg:                issuer "chandler@chandlerswift.com"
    gpg: Good signature from "Chandler Swift <chandler@chandlerswift.com>" [ultimate]
    Second commit
    03c3f6e gpg: Signature made Mon 13 Jul 2026 10:45:16 PM CDT
    gpg:                using RSA key FBF32CDBCC134B44FD29B66FA851D929D52FB93F
    gpg:                issuer "chandler@chandlerswift.com"
    gpg: Good signature from "Chandler Swift <chandler@chandlerswift.com>" [ultimate]
    Initial commit
    $ git history reword HEAD~
    $ git log --oneline --show-signature  # oops! where'd they go?
    5662b2c (HEAD -> main) Second commit
    6bf6830 Initial commit amended
This has pushed me back to the time-honored `git rebase -i` since I do want to keep my commits signed.
(comment deleted)
> Working with lots of changes in parallel on git can be painful. You end up juggling branches and commits, and running scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze.

I mean, just use stgit[1] to maintain a stack of patches instead of parallel branches, it's so much better. You can easily wrangle thousands of patches (aka commits) with stgit.

A lot of people, on first encountering stgit, read a bit about it, think "why do I need this? I can do the same thing with just plain ol' git.". Yeah, you can. But not at scale. Not practically. Not with thousands of commits. And it makes the case when you just have a few tens of commits absolutely trivial. Try it for awhile and you'll find it indispensible.

[1] https://stacked-git.github.io/

TIL, thx :-)

somewhat related Q:

how do you give two files the same ancestor? so git log will for each show the history to the beginnings of the originally unsplit file? useful for splitting large files.

> scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze

Complete bullshit. Might as well say "scary screwdriver that can turn up in your recturm if you so much as sneeze". Sure, I believe that might have happened to you (heard stories from friends that work in the emergency room), but I run rebase -i 10 times during the time I work on each branch (literally: I don't even care to write "proper" commit messages while writing the code, will reorganize and clean them up later anyway), and it never happened to me.

> Every 3 months, for the last 1.5 years, I try it out for a few days, really trying to make it part of my workflow but eventually I give up and go back to git.1

That's not really trying, let's assume you need 1 week to change ingrained workflows, so you just waste time every 3 months stopping right before the threshold. Better try once every year, but for a few*4 days...

The thing is, when you are rewriting history to change an old commit, you have to solve the little problem that git commit messages refer to hashes such as:

   This regression was caused in <hash> on December 19, 2017.
The fixup and rewrite of history has to ferret out these has references and fix them to the new hash of the same commit.

I have scripted this before!

By the way, the proper job of doing this recognizes abbreviated hashes also and fixes them up to equally abbreviated hashes.
I was uncomfortable with git until I read (the first 3 chapters of) the pro git book ( free here : https://git-scm.com/book/en/v2 ). It provides a great mental model of how git works under the hood. The UI of git - for better or worse - directly reflects its internals. And when I understood them, everything clicked into place.
git reflog is probably the Git command that has saved me the most stress. At some point you stop worrying about experimenting because you realize it's surprisingly hard to lose work permanently. Git is muuch more forgiving than it first appears.
These graphics are great. Makes for a skimmable high signal article, nice work!
I've been doing regular significant re-writes to my local Git commit history with relative ease for over a decade even without this new Git command.

I'm convinced that a big part of people often finding Git and rebase difficult is a user interface issue, having to know all the correct command line options and having to make your own mental model of what's happening and what you want to do, all makes it difficult to get a firm grasp on things.

I can't comment on what equivalent alternatives (especially on macOS/Linux as I'm a Windows user), but in terms of a UI for Git which exposes enormous power in an easy-to-use way I've found TortoiseGit to be spectacular and I especially like its rebase dialog:

https://tortoisegit.org/docs/tortoisegit/tgit-dug-rebase.htm...

Which you kick off from a context menu option from the commit line on the commit log you want to rebase onto with a simply named "Rebase <current reference> onto this" option:

https://tortoisegit.org/docs/tortoisegit/tgit-dug-showlog.ht...

It's super easy to re-order, split, combine, edit commits from here and it's obvious that will happen. If for whatever reason you decide you want to back out midway, you just abort and you're back to where you were.

I will concede there are aspects of a TortoiseGit I find a bit annoying, particularly that I feel I have to click around too much, instead of a shell extension I would prefer an app you launch with tabs or something, but I think this is a fundamental design principle of TortoiseGit, which followed the same principle as TortoiseSVN.

There is Git Extensions for Windows which seems nice at a glance, I tried it briefly, but I think I didn't stick with it either due to being unable to find an option I regularly used or I was just so used to TortoiseGit already.

Huh, TIL about `git commit —fixup`.