git: inspect and recover lost objects (unreachable or dangling)
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


git-lsu & git-lsd: Inspect unreachable or dangling objects

git-lsu: shows unreachable objects, but also contains code for git-lsd.
git-lsd: is a symlink to git-lsu, but will shows dangling objects.

How to use the tool (if you are bored, read the background below)

This tool is basically a wrapper and looper around following commands:
	git-fsck, git-ls-tree, git-show

For small projects, you can get away using the tool without using the
--input-file=<file> parameter, but I recommend using it, so the examples
below will be shown by using an input file.

Start by looking at the usage:
	$ git-lsu show

To list unreachable objects:
	$ git-lsu list > list-unreachable.out
	$ cat list-unreachable

To list dangling objects:
	$ git-lsd list > list-dangling.out
	$ cat list-dangling

Only the list command can pass additional parameters to git-fsck.
So if you still cannot find the object later, try using --no-reflog:
	$ git-lsu list --no-reflog > list-unreachable-noref.out
	$ git-lsd list --no-reflog > list-dangling-noref.out

In the next examples we are going to deal with unreachable objects
only. If you want to inspect dangling objects, use 'git-lsd' and the
list-dangling.out input file we created earlier.

List unreachable commit messages from new to old:
	$ git-lsu commit --input-file=list-unreachable.out

You can pass options to git-show by doing stuff like this:
	$ git-lsu commit --input-file=list-unreachable.out --stat
	$ git-lsu commit --input-file=list-unreachable.out \
		--no-newlines --quiet --oneline

You can display the tree object associated to each commit:
	$ git-lsu commit --input-file=list-unreachable.out --show-tree

You can display the complete tree associated to each commit:
	$ git-lsu commit --input-file=list-unreachable.out --dump-tree

List unreachable tree objects:
	$ git-lsu tree --input-file=list-unreachable.out

You can pass options to git-ls-tree by doing stuff like this:
	$ git-lsu tree --input-file=list-unreachable.out -r --abbrev

List unreachable blob objects:
	$ git-lsu blob --input-file=list-unreachable.out

Binary files will be displayed like this:
	(binary data: 9252 bytes)

List unreachable tag objects:
	$ git-lsu tag --input-file=list-unreachable.out

To restore a file:
	$ git show <SHA-1> > file

Dump all unreachable commit, tree, blob, tag objects to a file:
	$ git-lsu dump --input-file=list-unreachable.out dump-folder
NOTE: commits include stats+patches, trees are recursive.

Same as above, but only dump commit objects:
	$ git-lsu dump --input-file=list-unreachable.out \
		--commit dump-folder

Same as above, but only dump tree objects:
	$ git-lsu dump --input-file=list-unreachable.out \
		--tree dump-folder

Same as above, but only dump blob objects:
	$ git-lsu dump --input-file=list-unreachable.out \
		--blob dump-folder

Same as above, but only dump tag objects:
	$ git-lsu dump --input-file=list-unreachable.out \
		--tag dump-folder

If you want to re-use (or screwup) a given dump folder:
	$ git-lsu dump --input-file=list-unreachable.out \
		--force dump-folder

As you can see, there are a lot of options, and there is a lot of
overlap, so it is up to you to decide how you want to find your lost

Note that when you checkout an unreachable commit (yes, you can do
that), it will not show up as unreachable unless you use the --no-reflog
switch when using the 'list' command.


Examples #1: Recover from dropping a wrong stash

Create a list of unreachable objects:
	$ git-lsu list > list-unreachable.out

If you stash; you stash your index and your working (WIP) copy.

This will show the commits in chronological order:
	$ git-lsu commit --input-file=list-unreachable.out | less

If you remember when you have created your stash, write down the SHA-1
ID's of the 'index on <branch>' and 'WIP on <branch>' commits.

You can now find the SHA-1 of the blob by using this command:
	$ git-lsu commit --input-file=list-unreachable.out \
		--dump-tree | less

And restore the blob by using:
	$ git show <SHA-1> > file

Another way is checking out the commits and copy the files:
	$ git checkout <index SHA-1>
	$ cp ...
	$ git checkout <WIP SHA-1>
	$ cp ...

Examples #2: Recover from git reset --hard HEAD^

If you realized it in time and know the commit message:
	$ git reflog

And then using the commit ID, you can do this to undo:
	$ git reset --hard <SHA-1>

If you don't want to undo but copy some changes:
	$ git checkout <SHA-1>

In other cases, it might go faster creating a list:
	$ git-lsu list --no-reflog > list-unreachable-noref.out

Dump thes blobs:
	$ git-lsu dump --input-file=list-unreachable-noref.out \
		--blob dump-folder

Locate your changes:
	$ cd dump-folder/blob
	$ grep <changes> *

And if in doubt between several blobs, check the date of the commmit
in which they show up by checking the output of this command:
	$ git-lsu commit --input-file=list-unreachable-noref.out \
		--dump-tree | less

Example #3: ....

Please let me know in case I saved your day! Tell me what you did
wrong, which steps you tried, and how you were able to recover, ...

Some boring background about the tool and when to use it

This tool is designed to help you in case you did something really
stupid while using the git add, stash, rebase, reset, checkout and
maybe, probably, some others commands.

If you were lucky, you performed a 'git add' of the file before you
managed to cripple your file. If this was the case, your file is still
available from the index, and you can still retrieve it by running:

	$ git checkout-index <file>

But a lot can go wrong, let's name a few examples:

(1) You add something to the index, make few changes, test your
changes, think it's ok, add the changes to the index, and then discover
you managed to cripple your file before adding a second time to the

(2) You were working on something, stashed your changes, switched to
something else, stashed some other changes, and in the process, you
accidentally dropped the wrong stash, maybe even cleared the whole

(3) You ran the wrong reset/rebase command and completely screwed your
history .. well, you probably deserved it in this case :-)

The good news is: as soon as git touched that version, either by adding
it to the index, stashing it, committing it, or whatever; git still
knows about it (as long as you didn't fool around with repacking and
purging objects in the meantime).

This is where 'git fsck' comes in. You can try using:

	$ git fsck --lost-found

But it doesn't (yet?) work with additional options, so it doesn't always
restore the objects you lost. And if you have a lot of similar files,
you'll need to find the commit and tree object it belonged to first.

It's possible to find something, just a bit too cumbersome.
So if you ever tried this: this script might save you a lot of time.


This tool was designed to make it easy to either inspect dangling or
unreachable objects, or recover them. You are responsible for giving
this tool the correct pass-through options to the git commands it is
using. I am not planning to include all possible git commands in my
source code, or even support using every single one of them. You can
however try to convince me a certain option does not work well and why
it would be useful to support it.