哪些 git 命令执行完整性检查?

发布于 2024-10-31 01:48:07 字数 2546 浏览 7 评论 0 原文

为了确定用户多久会收到关于 git-1.7.4.1 对象数据库损坏的警告,我拉了一个位 switcheroo:

$ git init repo
Initialized empty Git repository in /tmp/repo/.git/
$ cd repo
$ echo 'very important info' >critical
$ git add critical
$ git commit -m critical
[master (root-commit) c4d6d90] critical
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 critical
$ git ls-tree HEAD
100644 blob 82d423c32c4bb2c52938088e0234db041bf4eaaf    critical
$ git show 82d423c32c4bb2c52938088e0234db041bf4eaaf
very important info
$ echo 'Very important info' | git hash-object --stdin -w
81a3797afe76d339db25c0f9c705a6caa47279c2
$ mv .git/objects/81/a3797afe76d339db25c0f9c705a6caa47279c2 \
     .git/objects/82/d423c32c4bb2c52938088e0234db041bf4eaaf

当然,git-fsck 注意到了,

$ git fsck
error: sha1 mismatch 82d423c32c4bb2c52938088e0234db041bf4eaaf

error: 82d423c32c4bb2c52938088e0234db041bf4eaaf: object corrupt or missing
missing blob 82d423c32c4bb2c52938088e0234db041bf4eaaf

但是 git -log 对更改感到满意

$ git log -p
commit c4d6d90467af9ffa94772795d5c5d191228933c1
Author: Greg Bacon <[email protected]>
Date:   Thu Apr 7 12:20:53 2011 -0500

    critical

diff --git a/critical b/critical
new file mode 100644
index 0000000..82d423c
--- /dev/null
+++ b/critical
@@ -0,0 +1 @@
+Very important info

git-checkout 也是如此。

$ rm critical 
$ git checkout .
$ cat critical 
Very important info

对 git-show 的特定调用揭示了损坏

$ git show 82d423c32c4bb2c52938088e0234db041bf4eaaf
error: sha1 mismatch 82d423c32c4bb2c52938088e0234db041bf4eaaf

fatal: bad object 82d423c32c4bb2c52938088e0234db041bf4eaaf

,但没有显示更广泛的损坏。

$ git show
commit c4d6d90467af9ffa94772795d5c5d191228933c1
Author: Greg Bacon <[email protected]>
Date:   Thu Apr 7 12:20:53 2011 -0500

    critical

diff --git a/critical b/critical
new file mode 100644
index 0000000..82d423c
--- /dev/null
+++ b/critical
@@ -0,0 +1 @@
+Very important info

甚至 git-clone 也没有注意到!

$ cd ..
$ git clone repo clone
Cloning into clone...
done.
$ cat clone/critical 
Very important info

特定 git 命令模式的完整列表是什么(例如,应该存在 git show $sha1,但不存在 git showgit show HEAD)执行完整性检查?

Trying to determine how quickly a user would be warned of corruption in the object database with git-1.7.4.1, I pulled a one-bit switcheroo:

$ git init repo
Initialized empty Git repository in /tmp/repo/.git/
$ cd repo
$ echo 'very important info' >critical
$ git add critical
$ git commit -m critical
[master (root-commit) c4d6d90] critical
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 critical
$ git ls-tree HEAD
100644 blob 82d423c32c4bb2c52938088e0234db041bf4eaaf    critical
$ git show 82d423c32c4bb2c52938088e0234db041bf4eaaf
very important info
$ echo 'Very important info' | git hash-object --stdin -w
81a3797afe76d339db25c0f9c705a6caa47279c2
$ mv .git/objects/81/a3797afe76d339db25c0f9c705a6caa47279c2 \
     .git/objects/82/d423c32c4bb2c52938088e0234db041bf4eaaf

Of course, git-fsck notices

$ git fsck
error: sha1 mismatch 82d423c32c4bb2c52938088e0234db041bf4eaaf

error: 82d423c32c4bb2c52938088e0234db041bf4eaaf: object corrupt or missing
missing blob 82d423c32c4bb2c52938088e0234db041bf4eaaf

but git-log is happy with the change

$ git log -p
commit c4d6d90467af9ffa94772795d5c5d191228933c1
Author: Greg Bacon <[email protected]>
Date:   Thu Apr 7 12:20:53 2011 -0500

    critical

diff --git a/critical b/critical
new file mode 100644
index 0000000..82d423c
--- /dev/null
+++ b/critical
@@ -0,0 +1 @@
+Very important info

as is git-checkout.

$ rm critical 
$ git checkout .
$ cat critical 
Very important info

A specific invocation of git-show reveals the corruption

$ git show 82d423c32c4bb2c52938088e0234db041bf4eaaf
error: sha1 mismatch 82d423c32c4bb2c52938088e0234db041bf4eaaf

fatal: bad object 82d423c32c4bb2c52938088e0234db041bf4eaaf

but not a broader one.

$ git show
commit c4d6d90467af9ffa94772795d5c5d191228933c1
Author: Greg Bacon <[email protected]>
Date:   Thu Apr 7 12:20:53 2011 -0500

    critical

diff --git a/critical b/critical
new file mode 100644
index 0000000..82d423c
--- /dev/null
+++ b/critical
@@ -0,0 +1 @@
+Very important info

Even git-clone doesn't notice!

$ cd ..
$ git clone repo clone
Cloning into clone...
done.
$ cat clone/critical 
Very important info

What is the full list of specific git command modes (e.g., git show $sha1 should be present but not git show or git show HEAD) that perform integrity checks?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

╰◇生如夏花灿烂 2024-11-07 01:48:07

以下是我如何找到这个问题,尽管我不会遍历每个源文件来找出执行检查的条件。 :)

克隆 git 的源代码:

git clone git://git.kernel.org/pub/scm/git/git.git

查看您关心的版本:

cd git
git checkout v1.7.1

查找错误消息:

git grep 'sha1 mismatch'

这将引导您到达 object.cparse_object 函数。现在查找该函数:

git grep parse_object

...并浏览 38 个文件,检查调用该函数的条件。

Here's how I would go about finding this out, although I'm not going to go through each source file to work out the conditions under which the check is performed. :)

Clone git's source code:

git clone git://git.kernel.org/pub/scm/git/git.git

Check out the version you care about:

cd git
git checkout v1.7.1

Look for that error message:

git grep 'sha1 mismatch'

That leads you to object.c and the parse_object function. Now look for that function:

git grep parse_object

... and go through the 38 files checking the conditions under which that function will be called.

风吹雨成花 2024-11-07 01:48:07

为了回应 Mark Longair 的回答,我启动了 cscope 并发现:(

请注意 cscope 如何有一个 curses 接口,并很好地集成到 Vim 中,以防你的兴趣被激起

Functions calling this function: parse_object

  File              Function                       Line
0 bundle.c          verify_bundle                   110 struct object *o = parse_object(e->sha1);
1 bundle.c          create_bundle                   242 struct object *object = parse_object(sha1);
2 bundle.c          create_bundle                   247 struct object *object = parse_object(sha1);
3 bundle.c          create_bundle                   323 obj = parse_object(sha1);
4 commit.c          lookup_commit_reference_gently   30 struct object *obj = deref_tag(parse_object(sha1), NULL, 0);
5 http-backend.c    show_text_ref                   372 struct object *o = parse_object(sha1);
6 http-push.c       one_remote_object               742 obj = parse_object(sha1);
7 http-push.c       add_remote_info_ref            1530 o = parse_object(ref->old_sha1);
8 log-tree.c        add_ref_decoration               93 struct object *obj = parse_object(sha1);
9 merge-recursive.c get_ref                        1664 object = deref_tag(parse_object(sha1), name, strlen(name));
a pack-refs.c       handle_one_ref                   43 struct object *o = parse_object(sha1);
b pretty.c          format_commit_one               835 parse_object(commit->object.sha1);
c reachable.c       add_one_reflog_ent              122 object = parse_object(osha1);
d reachable.c       add_one_reflog_ent              125 object = parse_object(nsha1);
e reachable.c       add_one_ref                     133 struct object *object = parse_object(sha1);
f reflog-walk.c     fake_reflog_parent              234 commit_info->commit = (struct commit *)parse_object(reflog->osha1);
g refs.c            peel_ref                        647 o = parse_object(base);
h refs.c            write_ref_sha1                 1452 o = parse_object(sha1);
i remote.c          ref_newer                      1482 o = deref_tag(parse_object(old_sha1), NULL, 0);
j remote.c          ref_newer                      1487 o = deref_tag(parse_object(new_sha1), NULL, 0);
k revision.c        add_head_to_pending             166 obj = parse_object(sha1);
l revision.c        get_reference                   176 object = parse_object(sha1);
m revision.c        handle_commit                   196 object = parse_object(tag->tagged->sha1);
n revision.c        handle_one_reflog_commit        855 struct object *o = parse_object(sha1);
o server-info.c     add_info_ref                     12 struct object *o = parse_object(sha1);
p sha1_name.c       peel_to_type                    508 o = parse_object(sha1);
q sha1_name.c       peel_to_type                    511 if (!o || (!o->parsed && !parse_object(o->sha1)))
r sha1_name.c       peel_onion                      573 o = parse_object(outer);
s sha1_name.c       peel_onion                      578 if (!o || (!o->parsed && !parse_object(o->sha1)))
t sha1_name.c       handle_one_ref                  698 struct object *object = parse_object(sha1);
u sha1_name.c       get_sha1_oneline                740 if (!parse_object(commit->object.sha1))
v tag.c             deref_tag                        16 o = parse_object(((struct tag *)o)->tagged->sha1);
w tree.c            parse_tree_indirect             271 struct object *obj = parse_object(sha1);
x tree.c            parse_tree_indirect             284 parse_object(obj->sha1);
y upload-pack.c     got_sha1                        342 o = parse_object(sha1);
z upload-pack.c     reachable                       382 parse_object(commit->object.sha1);
A upload-pack.c     receive_needs                   526 object = parse_object(sha1);
B upload-pack.c     send_ref                        644 struct object *o = parse_object(sha1);
C upload-pack.c     mark_our_ref                    670 struct object *o = parse_object(sha1);
D walker.c          loop                            182 parse_object(obj->sha1);

In response to Mark Longair's answer, I fired up cscope and found:

(note how cscope has a curses interface and integrates nicely into Vim in case your interest was piqued)

Functions calling this function: parse_object

  File              Function                       Line
0 bundle.c          verify_bundle                   110 struct object *o = parse_object(e->sha1);
1 bundle.c          create_bundle                   242 struct object *object = parse_object(sha1);
2 bundle.c          create_bundle                   247 struct object *object = parse_object(sha1);
3 bundle.c          create_bundle                   323 obj = parse_object(sha1);
4 commit.c          lookup_commit_reference_gently   30 struct object *obj = deref_tag(parse_object(sha1), NULL, 0);
5 http-backend.c    show_text_ref                   372 struct object *o = parse_object(sha1);
6 http-push.c       one_remote_object               742 obj = parse_object(sha1);
7 http-push.c       add_remote_info_ref            1530 o = parse_object(ref->old_sha1);
8 log-tree.c        add_ref_decoration               93 struct object *obj = parse_object(sha1);
9 merge-recursive.c get_ref                        1664 object = deref_tag(parse_object(sha1), name, strlen(name));
a pack-refs.c       handle_one_ref                   43 struct object *o = parse_object(sha1);
b pretty.c          format_commit_one               835 parse_object(commit->object.sha1);
c reachable.c       add_one_reflog_ent              122 object = parse_object(osha1);
d reachable.c       add_one_reflog_ent              125 object = parse_object(nsha1);
e reachable.c       add_one_ref                     133 struct object *object = parse_object(sha1);
f reflog-walk.c     fake_reflog_parent              234 commit_info->commit = (struct commit *)parse_object(reflog->osha1);
g refs.c            peel_ref                        647 o = parse_object(base);
h refs.c            write_ref_sha1                 1452 o = parse_object(sha1);
i remote.c          ref_newer                      1482 o = deref_tag(parse_object(old_sha1), NULL, 0);
j remote.c          ref_newer                      1487 o = deref_tag(parse_object(new_sha1), NULL, 0);
k revision.c        add_head_to_pending             166 obj = parse_object(sha1);
l revision.c        get_reference                   176 object = parse_object(sha1);
m revision.c        handle_commit                   196 object = parse_object(tag->tagged->sha1);
n revision.c        handle_one_reflog_commit        855 struct object *o = parse_object(sha1);
o server-info.c     add_info_ref                     12 struct object *o = parse_object(sha1);
p sha1_name.c       peel_to_type                    508 o = parse_object(sha1);
q sha1_name.c       peel_to_type                    511 if (!o || (!o->parsed && !parse_object(o->sha1)))
r sha1_name.c       peel_onion                      573 o = parse_object(outer);
s sha1_name.c       peel_onion                      578 if (!o || (!o->parsed && !parse_object(o->sha1)))
t sha1_name.c       handle_one_ref                  698 struct object *object = parse_object(sha1);
u sha1_name.c       get_sha1_oneline                740 if (!parse_object(commit->object.sha1))
v tag.c             deref_tag                        16 o = parse_object(((struct tag *)o)->tagged->sha1);
w tree.c            parse_tree_indirect             271 struct object *obj = parse_object(sha1);
x tree.c            parse_tree_indirect             284 parse_object(obj->sha1);
y upload-pack.c     got_sha1                        342 o = parse_object(sha1);
z upload-pack.c     reachable                       382 parse_object(commit->object.sha1);
A upload-pack.c     receive_needs                   526 object = parse_object(sha1);
B upload-pack.c     send_ref                        644 struct object *o = parse_object(sha1);
C upload-pack.c     mark_our_ref                    670 struct object *o = parse_object(sha1);
D walker.c          loop                            182 parse_object(obj->sha1);
谢绝鈎搭 2024-11-07 01:48:07

Git 2.38(2022 年第 3 季度)在 parse_object() 上添加了更多内容,

服务器端响应“git fetch"(man)git 克隆( man) 请求已得到优化,允许它发送对象存储中的对象,而无需重新计算和验证对象名称。

请参阅提交 945ed00(2022 年 9 月 7 日)和 提交 9a8c3c4, 提交 0bc2557提交 c868d8e(2022 年 9 月 6 日) )作者:杰夫·金 (peff)
(由 Junio C Hamano -- gitster -- 合并于 提交 8b2f027,2022 年 9 月 13 日)

parse_object():允许跳过哈希检查

签字人:杰夫·金

parse_object() 函数检查它解析的任何对象的对象哈希。
这是一个很好的功能,因为它意味着我们可以在正常使用期间捕获位损坏,而不是等待特定的 fsck 操作。

但它也可能很慢。
对于 blob 尤其值得注意,除了哈希检查之外,我们可以在不加载对象内容的情况下返回。

现在,人们可能想知道首先在 blob 上调用 parse_object() 的意义何在,但通常这不是故意的:我们从某个地方获得了一个 oid,但我们不知道类型,并想要一个对象结构。
对于提交和树,解析通常很有帮助;无论如何我们都要看看内容。
但对于 blob 来说情况就不那么正确了,我们可能会将它们作为可达性遍历等的一部分来收集,并且实际上并不关心它们里面有什么。
当然,斑点往往更大。

不过,我们不想仅仅丢弃 blob 的哈希检查。
在某些情况下,我们确实依赖它们(例如 <代码>rev-list(man) --verify-objects 使用 parse_object() 来检查它们)。
只有调用者知道他们将如何使用结果。
因此,我们可以通过提供一个特殊的标志来跳过哈希检查来帮助他们。

我们可以将其应用于 blob,因为它们将成为性能改进的主要来源。
但如果调用者不关心检查哈希值,我们也可以跳过其他对象类型的哈希值。
即使我们无法避免读取对象内容,我们仍然可以跳过实际的哈希计算。

如果这看起来会让 Git 抵御腐败的安全性降低一点,那么可能是这样。
但这是我们已经做出的一系列权衡的一部分。
例如,“rev-list --objects”不会打开它打印的 blob 内容。
当存在提交图时,我们完全跳过打开大多数提交。
重要的是在可以安全跳过检查的情况下使用此标志。
例如,当为获取提供包时,我们知道客户端将完全索引对象并自行执行连接检查。
服务器端重新散列 blob 本身几乎没有什么好处。
事实上,大多数时候我们不这样做!修订机制不会打开通过遍历到达的 blob,而只会打开通过“want”行直接请求的 blob。
如果应用得当,这项新功能在实践中不会降低任何安全性。


使用 Git 2.45(2024 年第 2 季度),第 5 批,upload-pack 的各个部分已已更新以限制相对于存储库大小的资源消耗,以防止滥用客户端。

请参阅 提交 6cd05e7提交 a6ca601, 提交5f64279提交 179776f提交 b065063提交 388b96d提交 720ba25提交fae9627(2024 年 2 月 28 日),作者:杰夫·金 (peff)
请参阅 提交 8c735b1(2024 年 2 月 28 日),作者:泰勒·布劳 (ttaylorr)
(由 Junio C Hamano -- gitster -- 合并于 提交 56d6084,2024 年 3 月 7 日)

upload-pack:使用 在更多地方进行 PARSE_OBJECT_SKIP_HASH_CHECK

签字人:杰夫·金

提交0bc2557upload-pack)中:跳过解析对象重新哈希,2022-09-06,Git v2.38.0-rc0 -- 合并列于批次#20)(上传包:跳过“想要”对象的解析对象重新哈希,2022-09-06),我们优化了来自客户端的 v2“想要”行的 parse_object() 调用,以便它们避免解析 blob,并且这样他们就使用提交图而不是从头开始解析提交对象。

我们应该将其扩展到另外两个地方:

  1. 我们在 got_oid() 函数中解析“have”对象。
    这些通常不会是非提交(与部分克隆中的“想要”行不同)。
    但我们仍然受益于提交图的使用。
  2. 对于 v0,“want”行在 receive_needs() 中解析。
    这些也不太可能是未提交的,因为默认情况下它们必须是参考提示。
    您可以设置一些配置选项来允许非提示对象,但您这样做主要是为了支持部分克隆,而最近足以支持部分克隆的客户端通常会使用 v2。

因此,我预计此更改不会大幅提高日常操作的性能。
但这两者都是可能的拒绝服务向量,攻击者可以通过发送大量对象来解析来浪费我们的时间(当然,我们可能会浪费更多时间向他们提供包,但我们会尽可能地尝试)为了在 pack-objects 中优化它;我们也应该在 upload-pack 中做我们可以做的事情)。

使用此补丁,使用 GIT_TEST_PROTOCOL_VERSION=0 运行 p5600 显示的结果与我们在 0bc2557(默认使用 v2 协议运行)。
以下是 linux.git 的数字:

测试 HEAD^ HEAD
-------------------------------------------------- ----------------------------
5600.3:结帐结果50.91(87.95+2.93) 41.75(79.00+3.18) -18.0%

或者对于更极端(和恶意)的情况,我们可以声称“拥有”git 中的每个 blob。 git 通过 v0 协议:

<前><代码>$ {
echo "0032want $(git rev-parse HEAD)"
打印0000
git cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype)' | git cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype)' |
perl -alne 'print "0032have $F[0]" if $F[1] eq "blob"'
} >输入

$ time ./git.old upload-pack 。 <输入>/dev/null
真实0m52.951s
用户0m51.633s
系统0m1.304s

$ time ./git.new upload-pack 。 <输入>/dev/null
实际0m0.261s
用户0m0.156s
系统0m0.105s

(请注意,由于使用了 hacky 协议,这些数字实际上并不计算包,因此这些数字代表 upload-pack 完成的原始 blob 解析工作)。

Git 2.38 (Q3 2022) adds more on parse_object()

The server side that responds to "git fetch"(man) and git clone(man) request has been optimized by allowing it to send objects in its object store without recomputing and validating the object names.

See commit 945ed00 (07 Sep 2022), and commit 9a8c3c4, commit 0bc2557, commit c868d8e (06 Sep 2022) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 8b2f027, 13 Sep 2022)

parse_object(): allow skipping hash check

Signed-off-by: Jeff King

The parse_object() function checks the object hash of any object it parses.
This is a nice feature, as it means we may catch bit corruption during normal use, rather than waiting for specific fsck operations.

But it also can be slow.
It's particularly noticeable for blobs, where except for the hash check, we could return without loading the object contents at all.

Now one may wonder what is the point of calling parse_object() on a blob in the first place then, but usually it's not intentional: we were fed an oid from somewhere, don't know the type, and want an object struct.
For commits and trees, the parsing is usually helpful; we're about to look at the contents anyway.
But this is less true for blobs, where we may be collecting them as part of a reachability traversal, etc, and don't actually care what's in them.
And blobs, of course, tend to be larger.

We don't want to just throw out the hash-checks for blobs, though.
We do depend on them in some circumstances (e.g., rev-list(man) --verify-objects uses parse_object() to check them).
It's only the callers that know how they're going to use the result.
And so we can help them by providing a special flag to skip the hash check.

We could just apply this to blobs, as they're going to be the main source of performance improvement.
But if a caller doesn't care about checking the hash, we might as well skip it for other object types, too.
Even though we can't avoid reading the object contents, we can still skip the actual hash computation.

If this seems like it is making Git a little bit less safe against corruption, it may be.
But it's part of a series of tradeoffs we're already making.
For instance, "rev-list --objects" does not open the contents of blobs it prints.
And when a commit graph is present, we skip opening most commits entirely.
The important thing will be to use this flag in cases where it's safe to skip the check.
For instance, when serving a pack for a fetch, we know the client will fully index the objects and do a connectivity check itself.
There's little to be gained from the server side re-hashing a blob itself.
And indeed, most of the time we don't! The revision machinery won't open up a blob reached by traversal, but only one requested directly with a "want" line.
So applied properly, this new feature shouldn't make anything less safe in practice.


With Git 2.45 (Q2 2024), batch 5, various parts of upload-pack has been updated to bound the resource consumption relative to the size of the repository to protect from abusive clients.

See commit 6cd05e7, commit a6ca601, commit 5f64279, commit 179776f, commit b065063, commit 388b96d, commit 720ba25, commit fae9627 (28 Feb 2024) by Jeff King (peff).
See commit 8c735b1 (28 Feb 2024) by Taylor Blau (ttaylorr).
(Merged by Junio C Hamano -- gitster -- in commit 56d6084, 07 Mar 2024)

upload-pack: use PARSE_OBJECT_SKIP_HASH_CHECK in more places

Signed-off-by: Jeff King

In commit 0bc2557 (upload-pack: skip parse-object re-hashing of , 2022-09-06, Git v2.38.0-rc0 -- merge listed in batch #20) (upload-pack: skip parse-object re-hashing of "want" objects, 2022-09-06), we optimized the parse_object() calls for v2 "want" lines from the client so that they avoided parsing blobs, and so that they used the commit-graph rather than parsing commit objects from scratch.

We should extend that to two other spots:

  1. We parse "have" objects in the got_oid() function.
    These won't generally be non-commits (unlike "want" lines from a partial clone).
    But we still benefit from the use of the commit-graph.
  2. For v0, the "want" lines are parsed in receive_needs().
    These are also less likely to be non-commits because by default they have to be ref tips.
    There are config options you might set to allow non-tip objects, but you'd mostly do so to support partial clones, and clients recent enough to support partial clone will generally speak v2 anyway.

So I don't expect this change to improve performance much for day-to-day operations.
But both are possible denial-of-service vectors, where an attacker can waste our time by sending over a large number of objects to parse (of course we may waste even more time serving a pack to them, but we try as much as possible to optimize that in pack-objects; we should do what we can here in upload-pack, too).

With this patch, running p5600 with GIT_TEST_PROTOCOL_VERSION=0 shows similar results to what we saw in 0bc2557 (which ran with the v2 protocol by default).
Here are the numbers for linux.git:

Test                          HEAD^                 HEAD
-----------------------------------------------------------------------------
5600.3: checkout of result    50.91(87.95+2.93)     41.75(79.00+3.18) -18.0%

Or for a more extreme (and malicious) case, we can claim to "have" every blob in git.git over the v0 protocol:

$ {
    echo "0032want $(git rev-parse HEAD)"
    printf 0000
    git cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype)' |
    perl -alne 'print "0032have $F[0]" if $F[1] eq "blob"'
  } >input

$ time ./git.old upload-pack . <input >/dev/null
real  0m52.951s
user  0m51.633s
sys   0m1.304s

$ time ./git.new upload-pack . <input >/dev/null
real  0m0.261s
user  0m0.156s
sys   0m0.105s

(Note that these don't actually compute a pack because of the hacky protocol usage, so those numbers are representing the raw blob-parsing effort done by upload-pack).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文