Git rebase -i is not that scary
Posted by vinhnx 1 day ago
Comments
Comment by flyingcircus3 1 day ago
I do still find myself tripping up on whether the next appropriate step is to make a commit or continue the rebase, as that is dependent on if you're in a merge conflict or just editing a commit. But even when I get that wrong, and collapse two commits together, abort saves the day.
Comment by hetman 1 day ago
Comment by xelxebar 1 day ago
https://www.man7.org/linux/man-pages/man7/gitrevisions.7.htm...
Comment by xorcist 1 day ago
Comment by brown9-2 1 day ago
Comment by conceptme 1 day ago
Comment by janpeuker 1 day ago
that means my hashes or their hashes or them keeping my hashes, I am never sure
Comment by selckin 1 day ago
Comment by delusional 1 day ago
Comment by selckin 1 day ago
Comment by roryirvine 11 hours ago
Not having to deal with all that is exactly what git is for.
Comment by Vinnl 8 hours ago
Comment by herywort 1 day ago
Comment by Vinnl 1 day ago
Comment by mikemcquaid 1 day ago
The biggest mistake most sources make when teaching about history rewriting is omitting these two lessons first:
- it’s easy to lose uncommitted data in Git and hard to lose committed data
- given this, learn how to use ‘git reflog’ to see what you’ve done and how to undo/redo it (as this post recommends but, even then, a little too late)
If you just get in the habit of constant committing and checking reflog: you’ll never lose data.
(Related lesson from my 10 years employed by GitHub: they almost never do the git gc you’d expect to remove commits so once you push a commit: it’s likely there forever and identifiable by that same hash from anywhere in the fork network. This can be bad/scary so be aware).
Comment by speq 1 day ago
Comment by douglee650 7 hours ago
Comment by codethief 1 day ago
Oh wow. Is there a way to trigger GC manually?
Comment by OneDeuxTriSeiGo 1 day ago
For git. You can run `git maintenance run` or the legacy command `git gc`.
Comment by mikemcquaid 1 day ago
Comment by dist-epoch 1 day ago
in case you are not aware of it already:
https://www.aikido.dev/blog/the-fork-awakens-why-githubs-inv...
Comment by xg15 1 day ago
I think I know what happens in principle (each step of a rebase does a merge of the commit from the list with the last rebased commit) but it's still often hard to understand which side of the conflict represents what, and what would be the desired outcome for that step in the history. So I tend to abort the rebase when I get a conflict and see if I can plan it differently so I can get it through without conflicts.
What I found good to know is that only actions that modify the actual changes in the history - reordering, deleting or editing commits - can cause conflicts. The other actions - reword, fixup or squash - only modify how the changes are grouped into commits and cannot cause conflicts.
So I usually do an interactive rebase in several passes: First a rebase that only reorders commits (or rarely does deletes or edits) and where I deal with the resulting conflicts, then a second pass for fixup or squash operations that can then use the reordered history from the first pass.
Rewords are both harmless and don't require any particular ordering, so can be done in any pass.
Comment by OJFord 1 day ago
Are you using diff3/zdiff3? I ask because you seem to be describing exactly the problem it solves, or at least the way I try to sell people on it.
Basically in addition to 'current' & 'incoming from the rebase' hunks you get 'parent commit of incoming from the rebase' – which allows you to see 'what was I trying to change', i.e. how does the intent of it apply to the different thing that's now on master (whatever I'm reading onto).
Comment by xg15 1 day ago
Comment by sensanaty 9 hours ago
Comment by xg15 9 hours ago
I think "git rerere" was built as a sort of bandaid for this. It doesn't really fix the problem but it at least makes it less annoying. (Haven't used it yet though)
Comment by wsc981 1 day ago
1. Abort rebase.
2. Squash all my commits into a single commit.
3. Rebase on target branch again.
Comment by nixpulvis 1 day ago
Comment by Glyptodon 1 day ago
Comment by hetman 1 day ago
Comment by seba_dos1 1 day ago
Comment by seba_dos1 1 day ago
merge.conflictStyle = zdiff3
made most of my fears regarding conflict resolution go away, as it right away gives me the stuff that I used to look for manually to understand the context of the conflict, which was probably the most error prone part of the process.Comment by mike_hock 1 day ago
Git was written with Linux in mind, where curating a clean commit history is more important than the code itself and warrants the extra hassle.
An actually usable rebase would probably require something like a meta history. But then the meta history would accumulate fixup "commits" and typos in commit messages so the OCD people will want to change that and we're back to square one. In practice, the two times per decade it actually makes business sense to dig through the history to find when a bug was introduced instead of just writing the 5-line fix, you can live with a couple of imperfect commits and merges.
Comment by jerf 1 day ago
Plus you can always take a note of the commit hash before you do anything crazy. But reflog means you don't have to.
Git really does have all the features you need. I wouldn't argue with anyone complaining about the UI to get there. But it's all in there somewhere.
Comment by ablob 1 day ago
Comment by newsoftheday 1 day ago
Comment by avaer 1 day ago
Git rebase has such foundational data structures and concepts that you couldn't pass a serious college programming course without grokking it.
The only reason someone would be scared of git rebase is:
a) they don't know the basics of programming/software engineering
b) they are not intellectually curious enough to look into how tf the software they use every day works
You probably shouldn't have engineers like that on your team.Comment by dtheodor 1 day ago
Comment by OneDeuxTriSeiGo 1 day ago
You do your development and use rebase to organise your code into logical commits/patches that can each be reviewed separately. This way when you do your review in github or on the mailing list or whatever you can review each logical change by going through and reviewing the commits separately (which you can do in github by selecting the commit in the dropdown for the review window).
And of course via email based workflows or "stacked patchset" workflows like what tangled provides then you can get deltas between revisions so that you can see what changed in a given commit between rev 1 and rev 2 so that you don't have to re-review the entire patchset/PR, only the stuff that matters (but still broken up into logical changes).
Comment by Valodim 1 day ago
Comment by chrysoprace 1 day ago
Comment by ablob 1 day ago
git config core.editor "vim"
I do agree that using the default editor is a mostly a bad choice due to it being vi/vim rather often.Comment by chrysoprace 1 day ago
A lot of talented developers that I've worked with use visual git clients exclusively, so imagine their horror when presented not only with an editor they don't use, but also a text-based menu (`git rebase -i`).
Comment by harpiaharpyja 1 day ago
Comment by Kuraj 23 hours ago
Comment by irishcoffee 1 day ago
Comment by rcxdude 1 day ago
Comment by irishcoffee 1 day ago
You’re very incorrect.
Comment by rcxdude 1 day ago
Comment by irishcoffee 1 day ago
Yes, good software is absolutely intuitive. Git is garbage.
Comment by rcxdude 22 hours ago
Comment by irishcoffee 22 hours ago
Comment by rcxdude 13 hours ago
Comment by xorcist 1 day ago
That's it. That basic knowledge will carry you far, and will be useful a decade from now. Those are the three best afternoons you can spend. Do it out of respect for the computer.
Comment by irishcoffee 1 day ago
Comment by boesboes 1 day ago
Comment by LAC-Tech 1 day ago
Comment by OneDeuxTriSeiGo 1 day ago
switch and restore replaced checkout. history is being developed to replace rebase for most common use cases. maintenance replaces gc. etc.
Comment by pasc1878 1 day ago
Comment by teaearlgraycold 1 day ago
Comment by LAC-Tech 1 day ago
- I find it uninteresting. My version control needs are very simple.
- Most teams I have been in use a small subset of it.
- It's confusing terms and inconsistent cli are huge warning signs to not go down that rabbithole. Today instead of learning Git I read some Tony Hoare, much better.
I've been at once place where they rebased, and it was awful. Complete waste of time. (great place otherwise though)
Comment by OneDeuxTriSeiGo 1 day ago
- https://git-scm.com/docs/gittutorial
- https://git-scm.com/docs/giteveryday
- https://git-scm.com/docs/gitworkflows
- https://git-scm.com/docs/gitfaq
- https://git-scm.com/cheat-sheet
Or if you want to sit down and really learn the nuts and bolts
Comment by LAC-Tech 1 day ago
Comment by OneDeuxTriSeiGo 6 hours ago
It really won't take hours. You probably read more than that just looking at HN for like 20 minutes.
Comment by rdevilla 1 day ago
Comment by seba_dos1 1 day ago
Comment by LAC-Tech 1 day ago
Comment by pajko 1 day ago
git reset HEAD^1 (NO --hard!)
git commit --patch ...
git rebase --continue
You want to add some pending changes to the previous commit? No problem: git commit --patch --amend ...
You want to move the pending changes to future commits? git stash
git rebase --continue
git stash popComment by LunicLynx 1 day ago
Comment by chrysoprace 1 day ago
Comment by formerly_proven 1 day ago
Comment by inigyou 1 day ago
Comment by pmontra 1 day ago
I guess a keyboard auto corrected i into I.
Comment by koolba 1 day ago
Comment by zahrevsky 1 day ago
Comment by Normal_gaussian 1 day ago
Comment by dietr1ch 1 day ago
I'm really not fond of having to `git rebase --interactive` just to drop all commits that are "already in master", especially when I forget this silly step and get a borked rebase.
Comment by xelxebar 1 day ago
git rebase -i master..HEAD
The gitrevisions(7) manpage is a good reference to keep in your back pocket, I find.https://www.man7.org/linux/man-pages/man7/gitrevisions.7.htm...
Comment by TurboSkyline 1 day ago
Comment by maxloh 1 day ago
Here's a GIF I found with Google: https://yogwang.site/2025/cursor-vscode-gitlens-rebase-edito...
Comment by QGQBGdeZREunxLe 23 hours ago
I also use git absorb (https://github.com/tummychow/git-absorb) and lazygit a lot (https://github.com/jesseduffield/lazygit).
Comment by t-writescode 1 day ago
Comment by TazeTSchnitzel 1 day ago
x git commit --amend --reset-author --no-edit
I use that one very frequently (after a fixup, of course) because I want the author date on amended commits to reflect the last time I edited them, not the first time I committed them.Comment by throw-the-towel 1 day ago
> git config --global alias.whatever_you_want 'commit --amend --reset-author --no-edit'
https://git-scm.com/book/ms/v2/Git-Basics-Git-AliasesComment by whateveracct 1 day ago
get ahead at work? split into commits and make it look like multiple days of work
work on your own IP during work hours? edit the timestamp to be outside work hours (i even have a script for this)
Comment by KoleSeise1277 1 day ago
Comment by russdill 1 day ago
Comment by zith 1 day ago
1. Everyone uses feature branches
2. Everyone cleans up their branch using interactive rebase on top of main before review
3. All merges have been freshly rebase on main
I think it works very well and keeps the history clean while preserving "each commit does one thing".
Comment by mr_mitm 1 day ago
The one time I suggested that, someone immediately came up to me trying to convince me that rebases are the most dangerous thing ever.
Comment by skitsofrandom 1 day ago
Comment by dijksterhuis 1 day ago
one of the first things i do in a new gitlab repo is set up ff+squash commit merges with the squash commit message template automatically pulling the MR title, link, description, authors etc.
%{title}
-
ref: %{reference}
url: %{url}
authored by: %{merge_request_author}
merged by: %{merged_by}
-
%{description}Comment by fisensee 1 day ago
Comment by mikeocool 1 day ago
git log --first-parent
git bisect --first-parent
Comment by xorcist 1 day ago
Comment by geon 1 day ago
Comment by boesboes 1 day ago
tbf, this says a lot more about the code base, my colleagues and the shitty, lazy culture at our company that leads to ZERO ownership and architecture ;)
Comment by cerved 1 day ago
git reset --hard @{1}
After a rebase to "undo" it.Comment by dsauerbrun 1 day ago
Imagine bushwhacking your way through a bunch of conflicts while rebasing on main... Now you realized that you needed to do some other work before your pr is ready for review... Now you need to rebase on main again and get to relive conflict hell again.
Maybe I'm one of the stupid incompetent people referred to in this post but I haven't figured out a way to deal with the having to solve the same merge conflicts when I rebase again :(
Comment by aneidon 1 day ago
Comment by dsauerbrun 1 day ago
Comment by conradludgate 1 day ago
It isn't particularly fast, but it uses bisect to find the first commit on the target branch that conflicts with your branch, then let's you rebase to that commit. You then repeat the process until you are caught up.
The idea is that solving one conflict many times is usually quite easy, especially if you know the conflicting commit messages, but solving many conflicts in one go is not so easy. This was inspired by me rebasing a 6 month old branch which refactored a file that happened to have many edits in between.
Comment by auscompgeek 1 day ago
Comment by gsliepen 1 day ago
Comment by prima-facie 1 day ago
FILE: .gitconfig
----------------
[alias]
ci = commit
fix = commit --fixup
[rebase]
autosquash = true
Now you can do quick commits as save-points, and squash all of them at the end. git tag last-good
git ci -am 'WIP'
git fix HEAD -a
git fix HEAD -a
…
git rebase -i last-goodComment by OneDeuxTriSeiGo 1 day ago
especially since if you are rebasing you may want to rebase your changes from one branch to another (i.e. move to top of main or from on top of one feature to another).
So instead you can just do git rebase --autosquash -i last-good or just git rebase --autosquash and let it squash it down for you.
Comment by zahlman 1 day ago
Comment by occz 1 day ago
Comment by bob1029 1 day ago
I have a simple rule where if the rebase cannot be solved within a few commit rewrites that I will restart the branch from latest master.
If you are suffering from really difficult rebase scenarios, it's likely that the senior developers are more at fault than the junior developers. The way you organize work over the codebase has the biggest impact on how things would conflict. If nothing ever does, rebasing is a trivial operation.
Comment by seba_dos1 1 day ago
Comment by beebix 1 day ago
Comment by vivzkestrel 1 day ago
- git rebase -i <commit-hash>^
- select edit
- git reset --soft HEAD~
- make some changes
- git add . && git commit -m "changes"
- git rebase --continue
- Am I using git rebase wrong?
Comment by noam_k 1 day ago
My preference, however, is creating a fixup commit and using rebase to squash it into the old one.
Edit: A sibling comment mentioned "git history fixup" which I'll have to try out.
Comment by barrkel 1 day ago
Comment by trescenzi 1 day ago
Comment by nicoburns 1 day ago
Comment by sodapopcan 1 day ago
Again, though, I still use a visual tool.
Comment by seba_dos1 1 day ago
Comment by dathinab 1 day ago
- create an empty commit with the branch name, type, ticket number etc. (with a small git script, `git issue 321 fix some things` -> `git switch -c 321-fix-some-things && git commit -m "fix(321): some things" --allow-empty`)
- `rebase -i` then shines when you have stacked commits where previous one have been merged _in a changed form (e.g. squashed)_. In such cases git often duplicates the already merged commits thinking they are part of your branch leading to endless dump conflicts, with a "marker" commit you can easily spot it in the `rebase -i` view and then also easily stripp them out by removing their lines
Comment by jordanboxer 1 day ago
git commit —fixup=<commit-id>
git rebase -i —autosquash
This is my best friendComment by tupton 1 day ago
git history fixup <commit-id>
https://git-scm.com/docs/git-history#Documentation/git-histo...Comment by raychis 1 day ago
Comment by eviks 1 day ago
The opposite is true, of course, for example: you move commits arround, start to resolve conflicts, and after a few steps you realize you can't, so when you
> you can bail out at any time. as aforementioned with git rebase --abort
Yep, except for all the work you've done resolving the conflict, that's "aborted"
> the old commits still exist in git’s object database, unreferenced but intact,
The best UI there is - some hidded data store you're, of course, intimately familiar with, so won't have any trouble getting data out of. Oh, wait, you didn't even know it existed? Tough luck, git gud to avoid data loss!
> botched rebase is a few minutes of you perusing through the reflog.
Unless, of course, your not that sharp to remember all the commits from their names and would also like to see the diff contents to connect to your code work. But that's just more minutes extra, not that big of a loss.
> there’s of course, the low-tech insurance policy: git branch backup-before-rebase
Finally some sensible advice, one that should be the default backup plan to save userst he trouble of wasting "few minutes" perusing the logs
Comment by BobbyTables2 1 day ago
Besides interactive rebase, my other favorite command is “git log —-oneline origin/master..HEAD”
It shows me exactly where I am…
Comment by vorticalbox 1 day ago
Comment by baq 1 day ago
Comment by letmeinhere 1 day ago
Comment by entrope 12 hours ago
This works because each commit gets a "change id" assigned that only changes when you say. When you create a new commit, edit its commit message, and edit files, you end up with three git commits with the same change id, but two of the git commits will be gc'ed eventually. (The change id is what you normally use to identify what's in the git commit graph.)
So even if you issue a command that destroys overwrite some important changes, jj has a good chance of remembering your worktree state.
Comment by code_lettuce 1 day ago
Comment by Normal_gaussian 1 day ago
pick a1b2c3d Add user model
s e4f5g6h Fix typo in user model
pick i7j8k9l Add login endpoint
s m0n1o2p WIP debugging login endpoint
s feedbee fixed login endpoint
s deadbee fixed login endpoint
s adebade fixed login endpoint
s abcdefg actually fixed login endpoint
Of course, I get reminded about f/fixup every now and then - think "golly, that will save a second or two" and promptly forget.Comment by newsicanuse 1 day ago
Comment by douglee650 1 day ago
Zero rebases since Fable 5.
Comment by collabs 1 day ago
Sure, if they want to they can later use `npm -g i` or whatever abomination they want but when we teach them, we should use full arguments, not aliases. please, people :(
Comment by fleventynine 1 day ago
Comment by nopurpose 1 day ago
TLDR; `jj edit <what_to_edit>; $EDITOR` will update a commit in the middle of the branch
Comment by fleventynine 11 hours ago
Comment by nopurpose 10 hours ago
Comment by cmrdporcupine 1 day ago
I know you can do this from within magit as well but I've never gotten into that workflow.
Comment by skydhash 1 day ago
Comment by ks6g10 1 day ago
Comment by dionian 1 day ago
Comment by nottorp 12 hours ago
Comment by jauntywundrkind 1 day ago
it's the one clear tool that i used all the time. moving to jj, it has lots of amazing tools starting with `jj edit` to go change the past safely & conveniently, with much less pain. but i miss the direct powerful data-driven experience of seeing the timeline in a text file, and picking what to do with it. sometimes.
imo every dev should work to get some competency with git rebase! it's an amazing tool. there's few other systems that give such direct control. it's top layer is, perhaps, the excel of version control?
Comment by doadfda 1 day ago
Comment by ed_mercer 1 day ago