• Show log

    Commit

  • Hash : a7d32d60
    Author : Patrick Steinhardt
    Date : 2019-07-20T18:46:32

    stash: avoid recomputing tree when committing worktree
    
    When creating a new stash, we need to create there separate
    commits storing differences stored in the index, untracked
    changes as well as differences in the working directory. The
    first two will only be done conditionally if the equivalent
    options "git stash --keep-index --include-untracked" are being
    passed to `git_stash_save`, but even when only creating a stash
    of worktree changes we're much slower than git.git. Using our new
    stash example:
    
    	$ time git stash
    	Saved working directory and index state WIP on (no branch): 2f7d9d47575e Linux 5.1.7
    
    	real    0m0.528s
    	user    0m0.309s
    	sys     0m0.381s
    
    	$ time lg2 stash
    
    	real    0m27.165s
    	user    0m13.645s
    	sys     0m6.403s
    
    As can be seen, libgit2 is more than 50x slower than git.git!
    
    When creating the stash commit that includes all worktree
    changes, we create a completely new index to prepare for the new
    commit and populate it with the entries contained in the index'
    tree. Here comes the catch: by populating the index with a tree's
    contents, we do not have any stat caches in the index. This means
    that we have to re-validate every single file from the worktree
    and see whether it has changed.
    
    The issue can be fixed by populating the new index with the
    repo's existing index instead of with the tree. This retains all
    stat cache information, and thus we really only need to check
    files that have changed stat information. This is semantically
    equivalent to what we previously did: previously, we used the
    tree of the commit computed from the index. Now we're just using
    the index directly.
    
    And, in fact, the cache is doing wonders:
    
    	time lg2 stash
    
    	real    0m1.836s
    	user    0m1.166s
    	sys     0m0.663s
    
    We're now performing 15x faster than before and are only 3x
    slower than git.git now.