Commit be18153b authored by Jacob Vosmaer's avatar Jacob Vosmaer Committed by Junio C Hamano
Browse files

builtin/pack-objects.c: avoid iterating all refs

In git-pack-objects, we iterate over all the tags if the --include-tag
option is passed on the command line. For some reason this uses
for_each_ref which is expensive if the repo has many refs. We should
use for_each_tag_ref instead.

Because the add_ref_tag callback will now only visit tags we
simplified it a bit.

The motivation for this change is that we observed performance issues
with a repository on that has 500,000 refs but only 2,000
tags. The fetch traffic on that repo is dominated by CI, and when we
changed CI to fetch with 'git fetch --no-tags' we saw a dramatic
change in the CPU profile of git-pack-objects. This lead us to this
particular ref walk. More details in:
gitlab-com/gl-infra/scalability#746 (comment 483546598)

Signed-off-by: Jacob Vosmaer's avatarJacob Vosmaer <>
Reviewed-by: default avatarTaylor Blau <>
Signed-off-by: default avatarJunio C Hamano <>
parent 66e871b6
......@@ -2803,13 +2803,11 @@ static void add_tag_chain(const struct object_id *oid)
static int add_ref_tag(const char *path, const struct object_id *oid, int flag, void *cb_data)
static int add_ref_tag(const char *tag, const struct object_id *oid, int flag, void *cb_data)
struct object_id peeled;
if (starts_with(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, &peeled) && /* peelable? */
obj_is_packed(&peeled)) /* object packed? */
if (!peel_ref(tag, &peeled) && obj_is_packed(&peeled))
return 0;
......@@ -3740,7 +3738,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (include_tag && nr_result)
for_each_ref(add_ref_tag, NULL);
for_each_tag_ref(add_ref_tag, NULL);
trace2_region_leave("pack-objects", "enumerate-objects",
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment