在我的回购,git diff而git stash这两个快速运行,在不到一秒钟。但是git stash -p,在显示第一个大块之前需要花费20秒钟。为什么会这样呢?
我注意到同样的问题。这种情况至少从一年多前就开始了,此后一直没有改善。\n我还在一个非常大的仓库上使用 git。不幸的是,在我的例子中,其中还有很多二进制数据,因为它\xe2\x80\x99s只是使用git_svn的SVN存储库的镜像,我的同事认为\xe2\x80\x99s是放置二进制测试数据的好主意进入回购协议。
\n\n没有答案,只是提示和猜测在哪里搜索:
\n\n它最大的区别在于,在调用stash -p函数的情况下。stash_patch否则stash_working_tree。
其中stash_patch有一些子进程称为执行其他 git 命令。其中之一是read-tree(参见man git-read-tree:)。最终命令如下所示:GIT_INDEX_FILE=index.stash.<PID> git read-tree HEAD。这实际上不需要时间。
下一步是另一个子进程调用GIT_INDEX_FILE=index.stash.<PID> git add--interactive --patch=stash -- <PATH>\xe2\x80\x93这是所有读取的来源,也是一直占用的地方。\n有趣的是:GIT_INDEX_FILE=index.stash.<PID> git status之后调用GIT_INDEX_FILE=index.stash.<PID> git read-tree HEAD与 一样昂贵git add--interactive。实际上add--interactive是一个perl脚本实现add -p. 我不\xe2\x80\x99t了解perl并且很难阅读这篇文章,但它可能会以某种方式检查工作目录状态并使用与git status.
基本思想是:
\n\n昂贵的部分是获取临时索引的工作目录的状态。为什么它\xe2\x80\x99这么贵我不知道\xe2\x80\x99。可能有一些缓存数据无效,并且它必须至少读取一定数量的工作副本中的所有文件,以便与临时索引进行比较,但要理解这一点,必须更深入地了解git status.
我尝试这样测量:
\n\nGIT_INDEX_FILE=.git/index.stash.test git read-tree HEAD\nGIT_TRACE_PERFORMANCE=/tmp/trace_status GIT_INDEX_FILE=.git/index.stash.test git st .\nRun Code Online (Sandbox Code Playgroud)\n\n结果如下:
\n\n20:31:20.439868 read-cache.c:2290 performance: 0.000269090 s: read cache .git/index.stash.test\n20:31:20.441368 preload-index.c:147 performance: 0.001419629 s: preload index\n20:32:15.568433 read-cache.c:1605 performance: 55.128484420 s: refresh index\n20:32:15.568611 diff-lib.c:251 performance: 0.000054503 s: diff-files\n20:32:15.568847 unpack-trees.c:1546 performance: 0.000004362 s: traverse_trees\n20:32:15.568868 unpack-trees.c:447 performance: 0.000008189 s: check_updates\n20:32:15.568874 unpack-trees.c:1643 performance: 0.000040807 s: unpack_trees\n20:32:15.568879 diff-lib.c:537 performance: 0.000079322 s: diff-index\n20:32:15.569115 name-hash.c:600 performance: 0.000197074 s: initialize name hash\n20:32:15.573785 dir.c:2326 performance: 0.004883714 s: read directory \n20:32:15.574904 read-cache.c:3017 performance: 0.001083674 s: write index, changed mask = 82\n20:32:15.575125 trace.c:475 performance: 55.135763475 s: git command: /usr/lib/git-core/git status .\n20:32:15.575421 trace.c:475 performance: 55.136831211 s: git command: git st .\nRun Code Online (Sandbox Code Playgroud)\n\n我的仓库看起来像这样:
\n\n>$ du -hd 1\n1,1M ./.idea\n74M ./code\n3,0G ./.git\n2,4G ./test-data\n5,5G .\n\nRun Code Online (Sandbox Code Playgroud)\n\n如果跟踪直接应用于:类似的图片git stash -p:
20:43:55.968088 read-cache.c:1605 performance: 59.716998605 s: refresh index\n20:43:55.969584 trace.c:475 performance: 59.719061140 s: git command: git update-index --refresh\n\nRun Code Online (Sandbox Code Playgroud)\n\n状态的手册页git update-index --refresh:
USING --REFRESH\n --refresh does not calculate a new sha1 file or bring the index up to date for mode/content changes. But what it does do is to "re-match" the stat information of a file with the index, so that you can refresh the index for a\n file that hasn\xe2\x80\x99t been changed but where the stat entry is out of date.\n\n For example, you\xe2\x80\x99d want to do this after doing a git read-tree, to link up the stat index details with the proper files.\nRun Code Online (Sandbox Code Playgroud)\n