On Mon, 18 Apr 2005, Russell King wrote:
> 
> Since this happened, I've been working out what state my tree is in,
> and I restored it back to a state where I had one dangling commit head,
> which was _my_ head.

For the future, if your tree gets messed up to the point where you say 
"screw it" and just want to go back in time, you can do this (it's 
equivalent to "undo" in BK speak):

        git log | less -S

        .. find which HEAD it was that you trusted..

In this case your HEAD before I merged with it was this one:

        df4449813c900973841d0fa5a9e9bc7186956e1e

So to get back to that one, you can do

        echo df4449813c900973841d0fa5a9e9bc7186956e1e > .git/HEAD

and now

        cat-file commit $(cat .git/HEAD) | head -1

gives you

        tree a43c4447b2edc9fb01a6369f10c1165de4494c88

so you can restore your checked-out state with

        read-tree a43c4447b2edc9fb01a6369f10c1165de4494c88
        checkout-cache -f -a
        update-cache --refresh

and your tree should be valid again.

Now, to remove any bogus objects, you can then run my "git-prune-script"
(look at it carefully first to make sure you realize what you are doing).

NOTE NOTE NOTE! This will _revert_ everything you had done after the 
"trusted" point. So you may not actually want to do this. Instead:

> It's very much like I somehow committed against the _parent_ of the
> head, rather than the head itself.

That's very common if you just forget to update your new ".git/HEAD" when 
you do a commit.

Again, it's the tools that make it a bit too easy to mess up. The 
"commit-tree" thing is supposed to really only be used from scripts (which 
would do something like

        result=$(commit-tree ...) && echo $result > .git/HEAD

but when doing things by hand, if you forget to update your HEAD, your 
next commit will be done against the wrong head, and you get dangling 
commits.

The good news is that this is not that hard to fix up. The _trees_ are all
correct, and the objects are all correct, so what you can do is just
generate a few new (proper) commit objects, with the right parents. Then
you can do the "git-prune-script" thing that will throw away the old
broken commits, since they won't be reachable from your new commits (even
though their _trees_ will be there and be the same).

So in this case:

        b4a9a5114b3c6da131a832a8e2cd1941161eb348
        +- e7905b2f22eb5d5308c9122b9c06c2d02473dd4f
           +- dc90c0db0dd5214aca5304fd17ccd741031e5493 <-- extra dangling head
           +- 488faba31f59c5960aabbb2a5877a0f2923937a3

you can do

        cat-file commit dc90c0db0dd5214aca5304fd17ccd741031e5493

to remind you what your old tree and commit message was, and then just 
re-commit that tree with the same message but with the proper parent:

        commit-tree xxxx -p 488faba31f59c5960aabbb2a5877a0f2923937a3

and then you need to do the same thing for the other commits (which will 
now need to be re-based to have the new commit-chain as their parents).

Then, when you fixed up the final one, remember to update .git/HEAD with 
its commit ID, and now the prune-thing will get rid of the old dangling 
commits that you just created new duplicates of.

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

Reply via email to