Rendered at 17:06:14 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
flyingcircus3 2 days ago [-]
After more than a decade of using git, I know that my comfort with rebase, and confidence that I wont make an error I can't undo, comes from knowing that I can always abort. And assuming it wasn't garbage collected, I can always get back to orphaned commits, or the commit before I rebased, as long as I keep their hashes. I can definitely look back on my less confident days as times when I wrongly assumed I was walking a tightrope where screwing up was painful and expensive, and easy to take the wrong path, and abort is the universal solvent to all of that.
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.
hetman 2 days ago [-]
You don't need to keep their hashes because git keeps them for you. If you realise too late that things went terribly wrong, you can get the pre-rebase hashes with "git reflog". (It can take a little getting used to knowing how to identify them quickly after a rebase but they're there.)
xelxebar 2 days ago [-]
Better yet, git reset ORIG_HEAD or whatever is usually sufficient[0]. The reflog is the general solution, but git's magic references do provide quite a few niceties.
This is a perfect use for tags. They allocate no extra storage space, and act as "savepoints" which you can refer to at any time. (Branches move, tags stay put.) They also guarantee that those loose ends are not garbage collected. Sometimes I delete a bunch of old ones, but any codebase of mine will at any time have a handful of old and probably useless tags. But that's ok.
brown9-2 1 days ago [-]
tags and branches are both just refs to the commit and can be used interchangeably for something like this. tags are not immutable, just in convention.
conceptme 21 hours ago [-]
Annotated tags have their own commit I believe that is ehy you should use annotated tags for release tags.
janpeuker 1 days ago [-]
> as long as I keep their hashes
that means my hashes or their hashes or them keeping my hashes, I am never sure
selckin 1 days ago [-]
you can just make a backup copy of .git or your entire project dir. When you get lost, just delete your .git, copy from the backup and try again
delusional 1 days ago [-]
You never need to do that. git-reflog(1) is the most general solution if you will ever need.
selckin 19 hours ago [-]
if you're a beginner thats going to be very difficult, restoring the git dir a few times makes the learning process much faster, till it all clicks and you don't need too anymore
roryirvine 7 hours ago [-]
But then you have multiple copies of your repo which is inevitably going to end up with a my_project_v2_FINAL_3b/ mess, reminiscent of how people used to manage files before version control.
Not having to deal with all that is exactly what git is for.
Vinnl 4 hours ago [-]
I'm pretty comfortable with Git, but I've still done this a number of times, and in my experience this situation is very evitable. After I've completed my gnarly process (whether successfully or unsuccessfully), I just delete the folder I don't want to use.
herywort 1 days ago [-]
Is this a joke? git's whole purpose is to save the history of your project and return to earlier versions when needed
Vinnl 1 days ago [-]
It's a super simple solution for which you can be certain that you have all the knowledge needed to perform the restore operation.
mikemcquaid 1 days ago [-]
I’ve used Git for 20 years now and wrote a book about it.
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).
douglee650 3 hours ago [-]
Ha, how many years spent reading it as re-flog and not ref-log. Flog the git!
speq 1 days ago [-]
The most important thing to happen to git in its entire history is jj as a better porcelain to git, so that you don't need to read entire books to get it right.
codethief 1 days ago [-]
> (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).
Oh wow. Is there a way to trigger GC manually?
OneDeuxTriSeiGo 1 days ago [-]
For github itself the answer is "contact them if you think you pushed a secret".
For git. You can run `git maintenance run` or the legacy command `git gc`.
mikemcquaid 1 days ago [-]
Unsure, no longer there. I think maybe just “contact support”.
dist-epoch 1 days ago [-]
> it’s likely there forever and identifiable by that same hash from anywhere in the fork network
I use interactive rebases frequently, but even then, I think conflicts happening during a rebase are often somewhat cryptic.
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.
OJFord 1 days ago [-]
> 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.
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).
xg15 1 days ago [-]
Thanks for the info! I didn't try that so far, but it sounds like it could really make that easier. Will give it a try!
sensanaty 5 hours ago [-]
I use it often as well, but if I'm rebasing more than a handful of commits it becomes very annoying and confusing if there's a conflict. For example, I often run into the situation where I'll get a conflict, I resolve that conflict on the first rebase step, but then the same conflict keeps popping up. Where did the resolution I just did disappear to? Why do I have to keep redoing the resolution?
xg15 5 hours ago [-]
Yep. I think that's a "normal" feature of how conflict resolution during rebases work: To perform your rebase, git merges each of the original commits into your new history, in turn. If one if those commits has a change that causes a conflict, the subsequent commits will likely have the same change and cause that same conflict again. And because your resolution is only for one commit, it will be "forgotten" in the next merge.
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)
In case of many commits with also many complex merge conflicts, I often find it easier to just:
1. Abort rebase.
2. Squash all my commits into a single commit.
3. Rebase on target branch again.
nixpulvis 2 days ago [-]
I feel like if you're scared of rebasing, you don't actually understand git.
Glyptodon 2 days ago [-]
My fear has never been rebasing itself, but that I make some kind of mistake with a random change conflict and don't notice it because it's not tested for directly. But I'm also not sure if that's categorically a git fear. (Edit: related to this, I think this sort of minor "itchy worry" is grounded in how sometimes conceptually simple diffs look messy during conflict resolution.)
hetman 2 days ago [-]
If all I'm doing with git rebase is reorganising my commits, and I have to deal with conflicts, after I'm done, I always git diff my pre-rebase head with post rebase head commit hash. I can quickly see I've messed something up if the diff isn't empty. For more complex tasks it's best to leave the rearranging until last, but where not possible, the diff is still pretty useful to double check my work.
seba_dos1 1 days ago [-]
range-diff can be useful for that too.
seba_dos1 1 days ago [-]
Setting:
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.
mike_hock 1 days ago [-]
Like all git operations that destroy history, it's a bit less scary than rm or unlink, because you can undo obvious fuckups using the reflog. Non-obvious fuckups will (by Murphy's law) only be detected long after the reflog has been GC'd, so it still risks losing work.
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.
jerf 2 days ago [-]
Reflog is, as the article says, the permission to do all kinds of crazy things, including rebasing. Once you realize any committed state is recoverable for a good period of time it really frees you.
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.
ablob 1 days ago [-]
I think the only missing thing for me would be to group commits, essentially squashing them for a clean history while allowing to unsquash them in case you need it.
newsoftheday 1 days ago [-]
git reflog can only help if the reflog history hasn't expired and been removed by a maintenance run.
avaer 1 days ago [-]
When I interview someone and they are scared of `git rebase -i` it's a huge red flag.
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.
dtheodor 1 days ago [-]
An interviewer asking me about git rebase is the huge red flag
OneDeuxTriSeiGo 1 days ago [-]
Understanding git rebase is important. You aren't expected to rebase mainline branches regularly but if your team operates on a merge/patchset workflow and isn't just squashing everything down onto main each PR you need to understand how to rebase your changes.
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).
Valodim 1 days ago [-]
Genuine question, why? It seems like a reasonable knowledge check that can be answered in a few sentences.
chrysoprace 1 days ago [-]
I wonder if it's because it opens in the default visual editor (typically vi/vim) and while I'm primarily a (neo)vim user now, it is certainly not the most intuitive editor to get started with without guidance.
ablob 1 days ago [-]
You can always set the editor in your --global or --local config though:
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.
chrysoprace 21 hours ago [-]
I know, but as you say that still presents a barrier to entry.
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`).
pipes 1 days ago [-]
I'm genuinely unsure why rebase interactive is more scary than rebase
bonzini 1 days ago [-]
Yeah I never use non-interactive rebase. Even if I don't need to edit the todo list, reading it gives me a confirmation of what git will do.
harpiaharpyja 1 days ago [-]
This notion that `git rebase -i` is some scary unusual thing is totally alien to me. Doing some minor cleanup on local history with rebase is a *basic* operation that I would have thought everyone would be using regularly.
Kuraj 19 hours ago [-]
I'm not scared of rebasing I'm scared of force pushing
irishcoffee 2 days ago [-]
The part where git needs to be “understood” is the entire problem. “Do one thing and do it well” was the whole mantra, which was completely ignored with the disaster that is git. It’s objectively awful.
rcxdude 1 days ago [-]
Absolutely everything in computing needs to be 'understood' to be used.
irishcoffee 1 days ago [-]
Really? How familiar are you with how inodes work on a spinning platter vs an eMMC? Can you speak intelligently about how virtual machines segregate their ram boundaries whilst still maintaining decent performance? What is your familiarity with FIPS?
You’re very incorrect.
rcxdude 23 hours ago [-]
And you were born with an understanding of how a keyboard and mouse worked or how windows seperated different GUI contexts and what all those symbols around them meant? I'm not saying you have to understand the nuts and bolts because abstractions exist but those abstractions still present you with a model and you need to understand that model to use them. People often present git's model mixed in with its nuts and bolts, which I think is unhelpful because the model is actually really simple and the nuts and bolts are not so important.
irishcoffee 22 hours ago [-]
Have you never seen a toddler touch a non-touch screen and be like “wtf?” Or watch a child holding mom’s phone swipe away a text message alert?
Yes, good software is absolutely intuitive. Git is garbage.
rcxdude 18 hours ago [-]
Because they've already learned a model of how devices with screens work, albeit an imperfect one. Children are pretty good at learning. Software and systems should be easy to learn, but it's not a case of no learning.
irishcoffee 18 hours ago [-]
So you agree then. People have been saying from inception that git isn’t intuitive.
rcxdude 9 hours ago [-]
I agree that git's UI is not particularly easy to learn, and it could be better in that regard (which is frustrating because its underlying model is about as simple as you can come up with, and I essentially can always think of what I want in that model easily but then have to google how to tell git to do it). What I object to is the idea that needing to understand something to use it is a problem.
xorcist 1 days ago [-]
You only have to learn three things to use a computer: Your shell, your editor, and your version control system.
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.
irishcoffee 1 days ago [-]
I am gainfully employed because I’m decent at those 3 things. I’m not sure why you assume I’m not. Fair point though.
boesboes 1 days ago [-]
sounds like someone accidentally delete your repo because they didn't understand git and did a dumdum :P
LAC-Tech 2 days ago [-]
yeah I would really love to see a subset of git with a sane cli. would switch in a heartbeat.
OneDeuxTriSeiGo 1 days ago [-]
Git has been re-designing their tooling over the last few years. Nowadays there exist really pleasant, easy to use versions of the main tools.
switch and restore replaced checkout. history is being developed to replace rebase for most common use cases. maintenance replaces gc. etc.
pasc1878 1 days ago [-]
Fossil?
teaearlgraycold 2 days ago [-]
It could be so much better. At the same time, it’s one of the core tools for a developer. You’ll learn it eventually. You’re going to be using version control for decades. I’ve met devs many years into their careers who don’t understand rebase. It’s like going to a metal shop and they’re complaining about the learning curve on their welder and half the tradesmen are still at a novice level.
LAC-Tech 2 days ago [-]
I still don't know it very well, and it's been well over a decade. I think it's a combination of a few things:
- 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)
OneDeuxTriSeiGo 1 days ago [-]
Have you ever read any of the introductory material that the git project itself maintains for teaching how to use the tool?
Looks like an incredibly dull way to waste hours of my finite life for microscopic benefit.
OneDeuxTriSeiGo 2 hours ago [-]
The first five links (i.e. not the book) are each only a few printed pages worth of text each or less. All together they are equivalent to like a single chapter of text in a book.
It really won't take hours. You probably read more than that just looking at HN for like 20 minutes.
Hendrikto 1 days ago [-]
Give it an hour or two. It is really not that complicated. A little bit of investment will pay huge dividends. Do yourself the favor.
LAC-Tech 1 days ago [-]
I could say the same for reading Tony Hoare.
rdevilla 2 days ago [-]
[dead]
seba_dos1 1 days ago [-]
[flagged]
LAC-Tech 2 days ago [-]
Correct on both counts.
pajko 2 days ago [-]
Why isn't the 'edit' command mentioned? It's one of the most useful features. It can be used for splitting commits, for example. Mark the commit you want to split to be edited. The commit replay is going to stop after that commit. Now:
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 pop
LunicLynx 1 days ago [-]
One additional thing I would mention ist that: When resolving conflicts never try to solve them for the final result. Consider each conflict without considering how the code will change in a later commit. I’ve seen people die a painful rebase death because of this.
chrysoprace 1 days ago [-]
Yeah like the other commenter below mentioned, `rerere` takes a lot of the pain out of layering rebased changes. It's important (IMO) to make sure each commit still contains a logical change and a working system, even with an incremental rebase.
formerly_proven 1 days ago [-]
rerere
inigyou 1 days ago [-]
this is not a cat on a keyboard. it is the name of a git command that does this.
pmontra 1 days ago [-]
The HN title is "Git rebase -I etc" but the post title is "Git rebase -i"
I guess a keyboard auto corrected i into I.
koolba 2 days ago [-]
That “-I” really needs to be lowercase.
zahrevsky 2 days ago [-]
Someone should collect all the cases when header capitalization on HN affected meaning
Normal_gaussian 2 days ago [-]
Yeah I got quite excited that there was somehow a better -i; its almost perfect clickbait
dietr1ch 2 days ago [-]
I was hoping for a rebase that recalled what your previous base commit of your branch.
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.
xelxebar 2 days ago [-]
Does this not do what you want?
git rebase -i master..HEAD
The gitrevisions(7) manpage is a good reference to keep in your back pocket, I find.
And, ironically, a lot of letters in the blog post need to be uppercase.
maxloh 2 days ago [-]
I found the VS Code GitLens extension to be a good abstraction for interactive rebase. It provides a drag-and-drop UI with a dropdown to select actions applied to each commit. That is much easier than editing a text file.
Oh that's really very clean, yeah. It's almost literally exactly what's in the text editor, just with a more friendly-for-mouse UX. They did very well.
TazeTSchnitzel 2 days ago [-]
I wish there were a shorthand for
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.
i edit my commit dates constantly for various reasons
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)
2 days ago [-]
2 days ago [-]
KoleSeise1277 2 days ago [-]
I still make a throwaway branch before a complicated rebase. It costs nothing and turns the whole operation into a low-stakes edit instead of a leap of faith.
russdill 2 days ago [-]
Yes, and you can diff the two branches when you are done!
zith 1 days ago [-]
A workflow I was introduced to and have worked with a lot in my teams is,
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".
mr_mitm 1 days ago [-]
I wish my team would at least use the rebase merge strategy by default to avoid branch graphs looking like the London tube network. Not in 10 years did I have an issue with that (okay, except accidentally rebasing deliberate no-ff merges).
The one time I suggested that, someone immediately came up to me trying to convince me that rebases are the most dangerous thing ever.
skitsofrandom 1 days ago [-]
I worked on a team that did this, + required feature branches to get squashed to a single commit before merge. On that commit, we'd require a very brief bullet list of changes, sometimes a POC, and a link to the PR. This made git blame a lot more helpful when debugging issues. I am a big fan of this approach.
dijksterhuis 1 days ago [-]
> On that commit, we'd require a very brief bullet list of changes, sometimes a POC, and a link to the PR.
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.
Git rebase isn't scary at all, what's scary is the git rebase cult. I'll probably die never really seeing the tangible benefit a meticulously curated git history provides but at least I saw a few hundred blog posts and hn comments declaring the moral failure that is not having the cleanest commit history. The cynic in me would say that people are over-identifying too much with their recent bikeshedding addiction (just like 10-page vim configs, custom built keyboards or whatever else promises them immense but immeasurable performance gains) but in reality I guess it's just completely different mental models about code. I have yet to look at any code or it's however dirty history and needed to consult a commit message to understand what it's there for but I'm looking forward to the day where one of my rebase colleagues fixes a bug with git bisect that wasn't efficiently fixable any other way.
mikeocool 1 days ago [-]
I continual find the amount of ink spilled on having a clean commit history amazing, when you can basically get all the same benefits with:
git log --first-parent
git bisect --first-parent
xorcist 1 days ago [-]
People are different, and I think we have to respect that. In my role I tend to have to fix problems in other people's code probably on a weekly basis. Commits that do too much, or too little, or are generally hard to understand are the number one reason this takes time. Crafting readable commits takes seconds out of your work day. Please be considerate to all your future colleagues.
geon 1 days ago [-]
I fix bugs will git bisect all the time. But it’s not practical if you don’t have a good commit history to begin with.
boesboes 1 days ago [-]
I use git history to understand wtf my colleagues, and myself, where doing and thinking 10 years ago. A well structured, squashed commit and a clean history helps A LOT. I can't tell you how often I find a 'Apply review changes' and 'Fix shit' commit with no context. I then need to go back in the blame history or find what branch/PR this belonged too on GH to find even the context of these changes.
Perhaps you don't work on the kind off crappy code bases I am dealing with, but a bit of git discipline saves a fuckton of frustrations.
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 ;)
cerved 1 days ago [-]
You dont need to open the reflog you can just
git reset --hard @{1}
After a rebase to "undo" it.
dsauerbrun 1 days ago [-]
Yeah it's not scary but it can be frustrating...
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 :(
aneidon 1 days ago [-]
git rerere?
dsauerbrun 1 days ago [-]
I'll give it a go next time! ty!
conradludgate 1 days ago [-]
I should publish it at some point (it's just a simple bash script), but I made a convenient alias `git bisect-rebase` which helps catch up very old branches.
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.
auscompgeek 1 days ago [-]
That somewhat sounds like the sort of thing git imerge does.
gsliepen 1 days ago [-]
If you do a rebase -i because you want to squash or fix some commits, then there's git commit --squash and git commit --fixup commands which will mark commits as intending to squash or fixup another commit, and then you can use git rebase --autosquash <base> to automatically do what you want in one go. Of course, often you forget to use the --squash/--fixup options or you can't be bothered to lookup the hash of the commit you want to fix, so you'll end up using git rebase -i anyway.
prima-facie 1 days ago [-]
I found the following config to bring a great QoL improvement:
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-good
OneDeuxTriSeiGo 1 days ago [-]
It's not recommended because you can just use the --autosquash flag. No reason to make it the default.
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.
zahlman 1 days ago [-]
I just use `git commit --amend` and then there is nothing to squash.
occz 1 days ago [-]
Adopting interactive rebasing along with curating my commits for the benefit of the reviewer has been the best upgrade I've made to my git usage in probably the last five years.
beebix 1 days ago [-]
A young dev who's still ambitious, gotta love it.
bob1029 2 days ago [-]
Rebase is scary if you are conflicting on many items.
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.
seba_dos1 1 days ago [-]
There's nothing scary about conflicts on cherry-picked commits. It's just sometimes tedious to resolve them one-by-one, and sometimes may just not be worth the effort if it can be done in a better way.
vivzkestrel 2 days ago [-]
- i often go back like 5 commits and make changes like this
- 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?
noam_k 2 days ago [-]
I wouldn't say it's wrong.
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.
barrkel 1 days ago [-]
No, but you would find jj solves this problem far more elegantly.
trescenzi 2 days ago [-]
Another git command I love using is `git add -p`. I always want to commit in chunks as I go but sometimes I wait to long or realize later I could have broken it up. Being able to select only pieces of a file to add to a specific commit is so great. Editing the chunks manually can be a bit intimidating but since it only stages the change you can always restore the file and try again if the diff doesn't look right after the add.
nicoburns 2 days ago [-]
That "git add -p" works from the command line is cool, but this is the one git task that I feel is significantly easier using a GUI tool (I use one specifically for this (and viewing diffs) while otherwise mostly using the command line).
sodapopcan 2 days ago [-]
I used to feel the same, and I still use a TUI tool, but after working with people who always used the CLI for this (who oddly otherwise were big into IDEs) it's actually an oddly really nice experience and not really any faster or slower. In fact, seeing a hunk at a time has this "focusing" affect on thinking about each change.
Again, though, I still use a visual tool.
seba_dos1 1 days ago [-]
Yeah, that's what I use the built-in `git gui` for.
dathinab 1 days ago [-]
For stacked commit workflows which merge into main with squashing I tend to:
- 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
jordanboxer 2 days ago [-]
git commit —fixup=<commit-id>
git rebase -i —autosquash
Nice balance of practical examples and mental models. One question though, how do you decide when to use interactive rebase versus relying on squash merges in platforms like GitHub.
eviks 1 days ago [-]
> it is very hard to actually lose work here, for three reasons.
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
BobbyTables2 2 days ago [-]
I also thought rebase was scary long ago. It is scary in the sense if one messes something up without realizing and then pushes to master…
Besides interactive rebase, my other favorite command is “git log —-oneline origin/master..HEAD”
It shows me exactly where I am…
vorticalbox 1 days ago [-]
I used to always have deep dread when having to use git but then I found [0]
After two decades of using git I'm either telling LLMs to do rebases for me or use jj (or both). Life's too short.
letmeinhere 1 days ago [-]
Just make sure you've committed and/or stashed first, as you don't really want to rely on the stochastic process to retain your local-only critical work product.
entrope 8 hours ago [-]
That's one of the nice features of jj: instead of having an index, the working tree is its own commit, and it tracks the history of that when you run most jj commands.
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.
code_lettuce 2 days ago [-]
Big rebase fan here. I find myself using squash the most.
Normal_gaussian 2 days 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.
newsicanuse 2 days ago [-]
I use rebase so much but it only feels comfortable because I follow a workflow while rebasing.
douglee650 1 days ago [-]
Most developers just have a linear view of git, which is fine. Should I really care that origins are just named nodes on combined graphs? Like, I just want to check in my code before I have to merge someone else's.
Zero rebases since Fable 5.
collabs 1 days ago [-]
please people, stop teaching newcomers short aliases. please teach them proper long terms --interactive is not much harder to type than -i. Why do we keep doing this? It isn't the 1970s anymore. even if we do this all day it will take what maybe 5 KiB more of ram or storage? if that? why teach people some Harry Potter incantations when we can teach them proper words?
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 :(
fleventynine 2 days ago [-]
I typically work with commit chains of at least 5 commits in various states of code review, so I spend at least 60% of my development time editing an old commit in the middle of a rebase -i.
1 days ago [-]
nopurpose 1 days ago [-]
You might find `jj` to help you there: all changesets have stable identifier and their content can be updated at any moment in-place.
TLDR; `jj edit <what_to_edit>; $EDITOR` will update a commit in the middle of the branch
fleventynine 7 hours ago [-]
Not an option for me until it supports submodules.
I really love the emacs interactive rebase mode, which comes up by default when you have EDITOR=emacs and do rebase -i.
I know you can do this from within magit as well but I've never gotten into that workflow.
skydhash 2 days ago [-]
The nice thing with magit is how easy it is to manipulate hunks and line, truly editing commits with a surgical precision, all with an handful of keybindings.
ks6g10 2 days ago [-]
Even just rebase fixup a commit that is a few commits below HEAD is just a few chords away. Use it many times a week when working.
dionian 2 days ago [-]
sometimes i wish mercurial won, if nothing else for the fact that i found its ux to be more enjoyable. I respect and use git, but never got comfortable with merging. im thankful AI can automate it for me now
nottorp 8 hours ago [-]
what does mercurial have to do with merging? a merge is a merge in both git and hg.
jauntywundrkind 2 days ago [-]
rebase interactive is so great, such a powerful tool.
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?
doadfda 1 days ago [-]
[dead]
ed_mercer 2 days ago [-]
I cannot recall the last time I committed manually, let alone rebase manually. An agent can do it for you faster and without making mistakes.
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.
https://www.man7.org/linux/man-pages/man7/gitrevisions.7.htm...
that means my hashes or their hashes or them keeping my hashes, I am never sure
Not having to deal with all that is exactly what git is for.
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).
Oh wow. Is there a way to trigger GC manually?
For git. You can run `git maintenance run` or the legacy command `git gc`.
in case you are not aware of it already:
https://www.aikido.dev/blog/the-fork-awakens-why-githubs-inv...
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.
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).
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)
https://git-scm.com/book/en/v2/Git-Tools-Rerere
1. Abort rebase.
2. Squash all my commits into a single commit.
3. Rebase on target branch again.
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.
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.
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:
You probably shouldn't have engineers like that on your team.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).
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`).
You’re very incorrect.
Yes, good software is absolutely intuitive. Git is garbage.
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.
switch and restore replaced checkout. history is being developed to replace rebase for most common use cases. maintenance replaces gc. etc.
- 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)
- 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
- https://git-scm.com/book/en/v2
It really won't take hours. You probably read more than that just looking at HN for like 20 minutes.
I guess a keyboard auto corrected i into I.
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.
https://www.man7.org/linux/man-pages/man7/gitrevisions.7.htm...
Here's a GIF I found with Google: https://yogwang.site/2025/cursor-vscode-gitlens-rebase-edito...
I also use git absorb (https://github.com/tummychow/git-absorb) and lazygit a lot (https://github.com/jesseduffield/lazygit).
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)
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".
The one time I suggested that, someone immediately came up to me trying to convince me that rebases are the most dangerous thing ever.
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.
git log --first-parent
git bisect --first-parent
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 ;)
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 :(
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.
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.
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.
- 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?
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.
Again, though, I still use a visual tool.
- 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
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
Besides interactive rebase, my other favorite command is “git log —-oneline origin/master..HEAD”
It shows me exactly where I am…
[0] https://ohshitgit.com/
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.
Zero rebases since Fable 5.
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 :(
TLDR; `jj edit <what_to_edit>; $EDITOR` will update a commit in the middle of the branch
I know you can do this from within magit as well but I've never gotten into that workflow.
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?