5 ms·
Ask HN: Is it me or Git rebase is kind of hard to understand?
I always struggle with the rebase command.
git merge is totally find, while git rebase is something mysterious for me.
Right now, after yesterday's typical work I checked git status and found out that I'm in the process of rebasing. I used git rebase --abort and lost my changes.
Is it lack of discipline to learn this, or it's indeed more complicated than merge?
venting ended
- Jimostar 4y agoHello everyone, I have some wise advice that will help you if you want to unwind and have a nice time. For instance, https://grantubodesexo.com/ https://grantubodesexo.com/ is perfect for a night out because it allows you to let off steam while having fun. I think you should have a look.
- savg 4y agoI'm the opposite and think rebasing is easier, but I am biased obviously since I have only used rebasing to solve merge conflicts. There are a couple ways of performing a git rebase, namely * git rebase * git rebase interactive (git rebase -i) * git rebase --onto I think following these videos may help and will explain it better than I can. What is Git Rebase? [Intermediate Git Tutorial] - https://www.youtube.com/watch?v=_UZEXUrj-Ds https://www.youtube.com/watch?v=_UZEXUrj-Ds Squashing Git commits with Interactive Rebase -https://www.youtube.com/watch?v=7IfkL8swmFw https://www.youtube.com/watch?v=7IfkL8swmFw How to undo git rebase using git reflog. - https://www.youtube.com/watch?v=qP4i3S2hujc&t=203s https://www.youtube.com/watch?v=qP4i3S2hujc&t=203s
- Akcium 4y agoI know little about git rebase, but the situation that just happened is kind of weird. I was working on my branch as usual. Today I checked git status and found out that I'm in the process of rebase. I was afraid a little, and decided to abort it. I lost my changes. When to git reflog, saw tons of commits, tried to cherry pick the one that has my changes. Now, I have my branch with my changes. But. If I pull from origin, I lost them. If I push force the branch, I'll erase other devs changes. It's so confusing =(
- seba_dos1 4y agoJust checkout (not cherry pick) the last commit from your reflog and point your branch to it and you'll be back exactly where you started. "git rebase --abort" simply did a checkout and pointed your branch to a place from before you started rebasing (that you apparently forgot about), you haven't lost anything.
- seba_dos1 4y agoIt's not. Just spend some time thinking about it not as a command to execute, but rather as an operation on a data structure you're working with (which is your repository) and it will click.
- solardev 4y agoI'm even more confused now :/
- seba_dos1 4y agoGit is a tool for manipulating graphs of states. You can traverse them (checkout), create new snapshots (commit), make and update pointers (tag and branch), calculate diffs and reapply them across different snapshots (rebase, cherry-pick, merge), and synchronize your graph with other repositories (push, fetch). Git commands and UI are just tools to let you work on this data structure. You should think in graph of commits first, and only then in commands that allow you to execute your plan. Like with any other data manipulation tool, there are often multiple ways to achieve the same thing. You may want to spend some time with https://blinry.itch.io/oh-my-git https://blinry.itch.io/oh-my-git - when you can actually imagine the data structure you're working on, it becomes obvious that rebase is nothing else than automated cherry-picking.
- btschaegg 4y agoTo pile on here: I fundamentally agree with GP, but from your description, I think you ran into a separate issue from how Git's data structure works, too: Git (the CLI tool) is stateful. Just as you modify the index (which, fundamentally, is shared global state in your repo) whenever you run `git add`, `git rebase` puts your repo in "rebase mode" (which, again, makes your repo global state). So if you worked for a while in an unfinished rebase (i.e. on a branch in "limbo" between the original and the rebased version), then realized that and ran `git rebase --abort`, what you told Git was: This rebase isn't working, please throw away my attempt and restore things to the way they where before I started it. And thus, you don't see your changes anymore. So, aside from GP's tip to learn the basic ideas behind Git's DAG (which I support whole-heartedly), here's some further advice: 1. Run `git status` religiously. Always. Basically, every second command should be `git status` until you're confident in your ability to infer the status yourself. Even then: Just `cd`d into your repo? Run `git status`! If that's too much typing work, set up a shell alias. 2. When reading up on Git's data structures, also take time to really learn rebase, with bells and whistles. My advice would be: You should be able to modify history with `git rebase -ir <commit>`. That means: Interactively, and with merge commits in between. And not just moving around commits, either, I mean at least: "Fixup", "reword" and "edit". This won't be a breeze to learn, but it pays off. And when you've understood it, you can be reasonably sure you can face most situations easily. 3. Now to the positive message :) You might not have lost your work. Did you check it in properly? Then it's still there. You'll find the commits somewhere in `git reflog`. You could cherry-pick them to your current (old and probably proper) branch position. On that note: Learn how to use and read `git reflog`. It's obscure, but it is your safety net in Git. If you check stuff in properly and often (you do, right?) you can pretty much always find your changes there, no matter what went wrong. Git rarely really ever throws information away after you officially handed it over. It follows a garbage collection process, and the time between unforced GCs is basically forever (months or so). Edit: I've got another one: 4. Use a good Git UI. I'm of the opinion that a commit graph for a reasonably small project should be kept readable and understandable. If you want to be conscious of your immediate commit history, I personally find Git UIs to be a much better tool to visualize it. Personally, I use and really like Git Fork [1] -- it's a small project without subscription fee, a more than fair price, and the developers are really responsive. Plus, it's actually pretty bug free, other than its competitors (*cough* Tower *cough*). The important thing here is: You should never solely rely on a Git UI, as they can never do all the things you want to be able to use Git for. Don't shy away from the CLI. But: I've found that for me, inspecting Git's history on the CLI is at least an order of magnitude worse than using an interactive UI (I believe due to inherent limitations around terminals). So you'll likey want to be able to use both. I'd wager that if you used a UI to check things in and look at the status of your repo, you'd have noticed the ongoing rebase rather quickly. [1]: https://git-fork.com/ https://git-fork.com/
- dyingkneepad 4y agoEverything Git is kind of hard to understand, but once it "clicks", you kinda start thinking it was easy all along. My suggestion is: before every rebase: - mkdir patches - cd patches - git format-patch HEAD~30 (in case you had 30 commits on top of the main branch but you can also "git format-patch $SHA" to get patches up to that SHA, not including) - git pull --rebase Then, if the rebase fails: - git checkout -b branchname-rebaseattempt origin/branch - make - git am 0001* - make - git am 0002* - git am --abort - etc This way you have a backup copy of every one of your commits as a patch file, and you can better understand and fix your conflict step-by-step without being "locked" in the process of a git-rebase. Sometimes when there are simple conflicts I edit the patch files themselves before applying.
- solardev 4y agoWhat's the advantage of this instead of just merging?
- seba_dos1 4y agoThere's no advantage for doing this at all. It's just duplicating the work git does for you already, but outside of git. I'd rather recommend spending some time with git to get familiar with your tooling, instead of working around your lack of familiarity this way. And when it comes to "what's an advantage of rebasing over merging" - those are two completely distinct operations that make you end up with different results, so there's no simple answer to that question (it's like "what's an advantage of bold font over italics?"). Sometimes you want to merge, sometimes you want to rebase. Once you can visualize your repository in your head, it becomes rather obvious when to use which one.
- mikewarot 4y agoGit appears to be a tool to manage merges using deltas. Git is actually a tool that simply stores everything in the current commit, and makes a nice graph showing Connections between those commits which theoretically represent deltas. All trouble arises when this abstraction breaks. It seems to me that the purpose of git merge is to simply allow you to work around broken abstractions. You can make the graph appear how you want, without having to jump through a bazillion unnecessary hoops to make a nice set of deltas. Or... I'm wrong and about to find out after hitting "add comment"
- Am4TIfIsER0ppos 4y agoHow the hell is it mysterious? It is just cherry-picking the commits then setting the branch pointer. Merge is the evil one because you can hide any changes you like in the commit.
- solardev 4y agoWhat does this mean?
- seba_dos1 4y agoMerge commit is just a regular commit that happens to have multiple parent commits - it doesn't have to match the state of its parent commits at all. However, you usually use `git merge` in order to create a commit that does in fact match the state of its parent commits, so some people (and even some UIs) don't expect it to diverge over regular conflict resolution - which is why it's easy to "hide" changes there that don't appear in any dedicated non-merge commit.
- Am4TIfIsER0ppos 4y agoYes. When you "resolve" "conflicts" you can add any changes you like. This means reading it you need to understand ++ -- +- -+ or to compare it to both parents and their parents to see what exactly was added. For example I recently had to do something with ffmpeg commit 522f87708653af3badcdc33be983bcc6009de49b which basically rewrites the code it is supposed to be merging. Fortunately for that commit it makes most sense to only compare it with its first parent. Things like that make me strongly prefer rebase.
- gardenhedge 4y agoGit is a good idea with a poor execution and naming
- mindcrash 4y ago"Within a converged timeline there are two timelines of events, so to create a new non-converged timeline you have to go back to the point in time where those timelines converged and add every event in the converged timelines in order in the new timeline. If things don't really work and a conflict emerges you, as the master of time, have to decide the right data to put into the new timeline" Hope it helps you breathe more easily :)