Hacker News new | past | comments | ask | show | jobs | submit login

The single best command that made working with `git rebase` infinite times easier is

    git reflog
At the very least it will stop you from "oh I fucked up the <rebase/merge/cherrypick/whatever> so bad that I must delete and clone the repo again".

At best you can salvage commits that have been rebased out, get back whatever you happened to checkout and basically it's the best command I found that does true to the "it's almost impossible to lose something in git once you've commited it"




You can also skip the reflog if you have a reference to the commit (the commit hash being the most reliable since it can't change), `git reset` is like the teleportation device for the git graph. Even if it's orphaned or dereferenced (due to rebase) it takes quite a while before git GC will remove it (two weeks is the default I think).

I feel like this should be introduced before any rebasing tutorial, or quite frankly any kind of more advanced git commands than commit/pull/push.

It's really important to know that it's ok to fuck (almost) everything up in order to make progress in learning. This even goes beyond git itself and onto the code it tracks - I've noticed some newbies will get stuck tip toeing around code worrying about "breaking it too much" when debugging something tricky... When I see that I tell them to park their work in a commit, then show them how to reliably restore the working tree to that point (reset --hard), then they can rip the codebase to shreds to properly zero in on the issue in short order.


> You can also skip the reflog if you have a reference to the commit [...]

And you always have it, in the `ORIG_HEAD` variable.


The name of this command always makes me think of "the floggings will continue until morale improves".


Important to note however is that the reflog is local and isn't pushed. Sometimes people panic when things aren't working and once someone asked me to fix their branch, but then it turns out they had deleted the local repo because they wanted to "start over again". Bad idea!


One thing I didn't know is that certain macOS apps keep their own version history of files, which you can access by opening the file in TextEdit (Xcode for instance will do this) and then File > Revert To > Browse all versions. So if you've truly lost work and can't restore with reflog or another git command, it's worth trying this.

https://support.apple.com/en-gb/guide/mac-help/mh40710/mac


I always read `reflog` as `re-flog` not `ref-log`. And, I was confused about the connection between flogging and the finding all git commits. It was much later that I made the connection.


Before you do something "dangerous" note the commit hash. You can always reset HEAD to that value.


Git has an easy way to mark a commit hash, even two. One is to create a branch. Another is to create a tag. Both are extremely cheap.


Yes, this another thing doesn't get said enough to a beginner:

A branch is nothing more than a pointer (or mark) to a commit.

This realisation along with the `git reflog` command I wrote above, made for a tremendous mental shift and suddenly almost everything around git just clicked together.


> A branch is nothing more than a pointer (or mark) to a commit.

A tag is.

A branch has the additional feature that it's a moving target with new commits, which is maybe not what you want in OP's case.


This (along with the fact that a commit is a state, not a patch) is really the most basic thing that every git tutorial should start with and you shouldn't move anywhere past that until you grasp it.

But what you usually get instead is "this is a command to commit, this is a command to push, and this one to pull, here's how you make a branch, have fun" - and then people complain that git is complicated because they end up with situations they don't understand. Well, duh - any new concept seems complicated until you take a closer look at it, and if you learn git this way you never actually did try to understand it. It's a data structure manipulation tool, so it's in your best interest to have at least some rough understanding of what data structure it operates on. Otherwise it's like trying to use a word processor without knowing how to write.

As another example, I find it completely backwards to teach `git pull` before `git fetch <remote> <ref>:<local_ref>`. How is one supposed to understand what `pull` does this way? However you imagine it at this stage, it's going to be wrong and will make you end up confused later on. Once you know how fetch works and what merge is, `git pull` becomes obvious. It doesn't work the other way around.


> A branch is nothing more than a pointer (or mark) to a commit.

Yep; the way I like to phrase it is "symlink". As in, .git/refs/heads literally contained symlinks in it pointing to commits. (It doesn't anymore because Windows.)


This is precisely what reflog shows you btw, i.e. all the things that HEAD has pointed to.

Running it after a rebase it's very informative, for example it helps clarify things like "ours" and "theirs".


Surely this is easier in every IDE which has a history window?


scrolling up in console usually gets you 90% of the way, git prints short commit ID for most ops.

> that does true to the "it's almost impossible to lose something in git once you've commited it"

Till GC doesn't eat it away. But IIRC default GC is few months


Reflog entries get removed after 90 days. Unreferenced objects after 14 days (since ctime).


There's before and after you know reflog


Or you can simply never rebase and always merge. I still don't understand why people think history-destroying rebase is a good idea, but that's just me.


Not just you; I agree. But few people seem to.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: