Finding lost changes with git fsck

Another tool exists in Git that can help you find and recover lost commits and even blobs (files), which is git fsck. The fsck command tests the object database and verifies the SHA-1 ID of the objects and the connections they make. The command can also be used to find objects that are not reachable from any named reference, as it tests all the objects found in the database, which are under the .git/objects folder.

Getting ready

Again, we'll use the hello world repository. If you make a fresh clone, make sure to run the scripts for this chapter (04_undo_dirty.sh), so there will be some objects for git fsck to consider. The scripts can be found on the book's homepage. If you just reset the master branch after performing the other recipes in the chapter, everything is ready.

We can create the fresh clone as follows:

$ git clone https://github.com/dvaske/hello_world_cookbook.git
$ cd hello_world_cookbook

We can reset an existing clone as follows:

$ cd hello_world_cookbook
$ git checkout master
$ git reset --hard origin master
HEAD is now at 3061dc6 Adds Java version of 'hello world'

How to do it...

  1. Let's look for the unreachable objects in the database:
    $ git fsck --unreachable
    Checking object directories: 100% (256/256), done.
    unreachable commit 147240ad0297f85c9ca3ed513906d4b75209e83d
    unreachable blob b16cf63ab66605f9505c17c5affd88b34c9150ce
    unreachable commit 4c3b1e10d8876cd507bcf2072c85cc474f7fb93b
    

    Note

    The object's ID, the SHA-1 hash, will not be the same if you perform the example on your computer, as the committer, author, and timestamp will be different.

  2. We found two commits and one blob. Let's take a closer look at each of them; the blob first:
    git show b16cf63ab66605f9505c17c5affd88b34c9150ce
    #include <stdio.h>
    
    void say_hello(void) {
            printf("hello, world
    ");
    }
    
    int main(void){
            say_hello();
            return 0;
    }
    

    So the blob is the hello_world.c file from the example which stashing away your changes before resetting a commit. Here we stashed away the file, performed a reset, and resurrected the file from the stash, but we never actually performed a commit. The stash command, however, did add the file to the database, so it could find it again, and the file will continue to be there until the garbage collection kicks in or forever if it is referenced by a commit in the general history.

  3. Let's look closer at the two commits:
    $ git show 147240ad0297f85c9ca3ed513906d4b75209e83d
    commit 147240ad0297f85c9ca3ed513906d4b75209e83d
    Merge: 3061dc6 4c3b1e1
    Author: Aske Olsson <[email protected]>
    Date:   Thu Mar 13 23:19:37 2014 +0100
    
        WIP on master: 3061dc6 Adds Java version of 'hello world'
    
    diff --cc hello_world.c
    index 881ef55,881ef55..b16cf63
    --- a/hello_world.c
    +++ b/hello_world.c
    @@@ -1,7 -1,7 +1,10 @@@
      #include <stdio.h>
    
    --int main(void){
    ++void say_hello(void) {
            printf("hello, world
    ");
    ++}
    
    ++int main(void){
    ++  say_hello();
            return 0;
    --}
    ++}
    
    $ git show 4c3b1e10d8876cd507bcf2072c85cc474f7fb93b
    commit 4c3b1e10d8876cd507bcf2072c85cc474f7fb93b
    Author: Aske Olsson <[email protected]>
    Date:   Thu Mar 13 23:19:37 2014 +0100
    
        index on master: 3061dc6 Adds Java version of 'hello world'
    

    Both the commits are actually commits we made when we stashed away our changes in the previous example. The stash command creates a commit object with the contents of the staging area, and a merge commit merging HEAD and the commit with the index with the content of the working directory (tracked files only). As we resurrected our stashed changes in the previous example, we no longer have any reference pointing at the preceding commits; therefore, they are found by git fsck.

How it works...

The git fsck command will test all the objects found under the .git/objects folder. When the --unreachable option is given, it will report the objects found that can't be reached from another reference; the reference can be a branch, a tag, a commit, a tree, the reflog, or stashed away changes.

See also

  • Refer to Chapter 12, Tips and Tricks, for more information on the git stash command
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset