miércoles, 6 de julio de 2011

Snapshots motherf*cker, do you speak it?


Today, I'll just snap a recipe for a use case that starts to crop up when evolving from a total git beginner to not-so-noob-git-user. git reset

Here's the diagram:



Ok, now screw it.

The main problem when thinking about how git works is thinking in the wrong way. You've been told hundreds of times that git works differently from EVERY other versioning system around, and you keep forgetting these concepts every now and then.

The diagram before is a diagram of where git moves your changes when you do a given reset command. git reset --soft foo moves the changes from commit 'foo' till HEAD to the index.

YOU'RE THINKING IT WRONG.

Remeber that you've been told that git records only snapshots? Well, think about it. When you want to reset your repo to the past, if you have a clean working directory and index. HEAD,index and wd are all in the same state. That means that All trees contain the same. THE SAME. If you are thinking that your wd has some files, that the index is empty (Delta is null) and same (or kind of) for the repo, you're thinking it WRONG again.

Now, if you go and look git help reset, and this MJD's post about git reset.

Then it's kind of easy to understand what it does, and in which state will leave your repo, index and ass.

(take the italics notes as if you just reseted the most recent commit, if you reset to older ones, all changes are accumulated)
  • git reset --soft just updates your HEAD. Changes are in the stage, ready to be commited without that nice 'fdsajflkdsajflkasdf' commit message. You're in the moment before you commited.
  • git reset --mixed updates your HEAD and your index accordingly. That means that probably, if you're reseting to past commits all changes from the target commit till now will be only in your wd. You're in the moment before you added files.
  • git reset --hard updates everything. You're in the moment after you commited the commit (O RLY?) so you lost everything you did after the commit.

Btw, Take all this post with a grain of salt. I just had an 'AHA!' moment I had to share. Probably it's not *very* technically accurate. I haven't even tried what happens on detached heads and other bizarre situations... yeah, I'm a sucker.

man git-reset contains lots of tables and info, but IMHO, naming the states of files A B C D lead to harder understanding that if they'd have been D C B A.

And now, a doubt for the lazyweb:
git reset hard does not allow you to recover your state. gitk --all does not show anything from HEAD on. but git reflog does show it. And I'd swear gitk --all worked 2 days ago....

Addendum: Here's a great article on git reset that appeared a week after my finding. Really well explained, with graphics, tables and everything.