为什么git stash -p需要很长时间才能启动?

Tor*_*erg 5 git git-stash

在我的回购,git diffgit stash这两个快速运行,在不到一秒钟。但是git stash -p,在显示第一个大块之前需要花费20秒钟。为什么会这样呢?

Pet*_*ter 1

我注意到同样的问题。这种情况至少从一年多前就开始了,此后一直没有改善。\n我还在一个非常大的仓库上使用 git。不幸的是,在我的例子中,其中还有很多二进制数据,因为它\xe2\x80\x99s只是使用git_svn的SVN存储库的镜像,我的同事认为\xe2\x80\x99s是放置二进制测试数据的好主意进入回购协议。

\n\n

没有答案,只是提示和猜测在哪里搜索:

\n\n
    \n
  • 它最大的区别在于,在调用stash -p函数的情况下。stash_patch否则stash_working_tree

  • \n
  • 其中stash_patch有一些子进程称为执行其他 git 命令。其中之一是read-tree(参见man git-read-tree:)。最终命令如下所示:GIT_INDEX_FILE=index.stash.<PID> git read-tree HEAD。这实际上不需要时间。

  • \n
  • 下一步是另一个子进程调用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\n
      \n
    • 从 HEAD 创建临时索引
    • \n
    • 交互式添加对该索引的更改
    • \n
    • 将更改后的临时索引保存到树状结构中
    • \n
  • \n
  • 昂贵的部分是获取临时索引的工作目录的状态。为什么它\xe2\x80\x99这么贵我不知道\xe2\x80\x99。可能有一些缓存数据无效,并且它必须至少读取一定数量的工作副本中的所有文件,以便与临时索引进行比较,但要理解这一点,必须更深入地了解git status.

  • \n
\n\n

我尝试这样测量:

\n\n
GIT_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 .\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果如下:

\n\n
20: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 .\n
Run 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\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果跟踪直接应用于:类似的图片git stash -p

\n\n
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\n
Run Code Online (Sandbox Code Playgroud)\n\n

状态的手册页git update-index --refresh

\n\n
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.\n
Run Code Online (Sandbox Code Playgroud)\n