Re: Git rescue mission

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Wed, 7 Feb 2007, Bill Lear wrote:
> 
> I have a public bare repo on my machine that I have cloned to make a
> private repo.  I just want to sync my branches on my public and
> private repos.  I do not want to merge across branches, I just want to
> "sync".

Ok, others already replied, but here's a few rules to ease your mind in 
general:

 - First off: you can always _trivially_ get back to whatever state you 
   had before, as long as you committed it, and didn't have any dirty 
   state (uncommitted patches) in your working tree.

This is something that it's worth repeating, and even perhaps 
experimenting with to get really comfortable with. Why? Because once you 
learn to get back to any random state you had before, and once you are 
comfortable with that, you suddenly lose the fear of experimenting. 
Whatever you screw up, if you're confident you can get back, who cares?

So the "get back from a mistake" should probably be at the very front of 
our manuals and tutorials. I don't think it currently is, but it's 
actually not that hard. There's just one command to remember: "git reset", 
and the only issue you might ever have with it is:

 - make sure you're on the right branch first! If the problem you had is 
   that you're on the wrong branch, switch branches first! Don't try to 
   make the wrong branch "look right". But once you know you're on the 
   right branch, you know that "git reset" is your friend to getting it 
   anywhere you want.

 - do you want to throw away all your working tree changes (and if 
   you screwed up some git operation, the answer is usually "Yes!"). If 
   so, add the "--hard" flag. It's not on by default, exactly because it 
   *will* throw away all state in your tracked working tree, and reset it 
   to whatever you want to go back to.

 - exactly *what* do you want to go back to? The default is to go back to 
   the state at the last successful commit, but sometimes what you screwed 
   up was exactly the last commit (eg an unintentional "pull" that 
   actually succeeded), and then you need to tell it *what* to reset to.

That's really all there is to it. It's really simple, although especially 
the second point can take some practice to get right.

So NORMALLY, if you did something bad - say, you edited a file, and just 
realized that the whole edit was just crap, and you want to start over - 
you just do a simple

	git reset --hard

and it will just reset all your git state to the last commit you did. 

This is what you'd do in this case, when you had a "git pull" that simply 
*failed* due to conflicts, and you realize that you didn't do that merge 
at all.

However, what happens if you actually do a "git pull" that doesn't have 
any conflicts (or at least they merge fine), so the pull actually 
*succeeds*, but you realize that wasn't what you wanted to do at all?

In that case, you need to say

	git reset --hard <point-you-want-to-go-back-to>

to just reset to the previous state. Now we get to that "how do I figure 
out what state that was?" part of the question, and usually it's trivial 
to answer.

For example, a command like "git pull" will leave a special magic name 
around to tell you what the original HEAD was before the pull, and that 
magic name is (surprise surprise) called ORIG_HEAD. So if the pull 
succeeded, but you realized it was an error (perhaps you had even intended 
to do it, but once you pulled, you just saw that what you pulled was crap, 
so you decide that you didn't really want to do it after all), you can 
just do

	git reset --hard ORIG_HEAD

and you're back to where you were _before_ the pull.

It really is that easy. And once you get comfortable with it, and you 
really know deep down how easy it is, that should just relax you a lot. 
When you go "AIEE! I made a horrible mistake!" you should just laugh, and 
say "and I don't *care*, because I can just trivially undo it!".

Now, usually it's really as simple as just using ORIG_HEAD (or the 
top-of-the-branch itself when the pull simply failed), but you can 
actually do it for any commit. Say, you've worked for a week, and have 
committed five or six things (and you don't even quite remember), and you 
are just weary, and realize that IT IS ALL CRAP!

Now, before you just decide to drown your sorrows in a bottle (or, 
perhaps, the morning after), you realize that you haven't actually pushed 
it out to anybody else yet (because it wasn't ready anyway), and that you 
can just undo the whole thing!

So what do you do?

You just fire up gitk, or whatever your favourite history viewer is (git 
log, qgit, whatever), and you select the last good commit by hand, and do

	git reset --hard <selected-commit-sha1-name>

which you just cut-and-paste from your history viewer. And magic happens. 
It's all gone, and you're now at that old state in history, and all your 
crap is gone, gone, gone. You can now have a drink or five, happy in the 
knowledge that you just wasted five days of your life, but nobody will 
ever even know your dark dirty little secret, and hopefully you're getting 
paid by the hour, not by the end result anyway.

Of course, if you have reflogs enabled (see previous discussions), it's 
even easier. In particular, it's easier if you do a "git reset" to some 
other point in history, and suddenly realize that what you want to undo is 
really that "git reset" itself ;)

(Even if you undo things, that's also recoverable, as long as you haven't 
done any garbage collection. But it can be harder, because now you won't 
get "git log" or "gitk" to show the stuff you undid, so this is where 
reflogs can save your bacon, since they will remember the old stuff too. 
Without reflogs, you either need to have it in ORIG_HEAD, or you need to 
run "git fsck-objects" and look at all the dangling commits by hand).

So be happy. "git reset" can be dangerous (you *are* throwing things 
away), but it's also very powerful, and pretty easy to use. And git makes 
it fairly hard to *really* throw anything committed away, so even if you 
undo something, and realize you want to re-do it again, it's possible to 
go back - at most it's just a bit more involved to *find* the place to go 
back to.

One final (and unrelated) note. If all you want to do is "sync up", and 
not actually merge anything new into your current branch, you should just 
do "git fetch". Not "git pull". Doing a "pull" implies merging into your 
current branch, and thus does more than just "sync up" the branches you 
are tracking.

			Linus


-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]