Skip to content

Commit 8e55634

Browse files
pks-tgitster
authored andcommitted
fetch: avoid lookup of commits when not appending to FETCH_HEAD
When fetching from a remote repository we will by default write what has been fetched into the special FETCH_HEAD reference. The order in which references are written depends on whether the reference is for merge or not, which, despite some other conditions, is also determined based on whether the old object ID the reference is being updated from actually exists in the repository. To write FETCH_HEAD we thus loop through all references thrice: once for the references that are about to be merged, once for the references that are not for merge, and finally for all references that are ignored. For every iteration, we then look up the old object ID to determine whether the referenced object exists so that we can label it as "not-for-merge" if it doesn't exist. It goes without saying that this can be expensive in case where we are fetching a lot of references. While this is hard to avoid in the case where we're writing FETCH_HEAD, users can in fact ask us to skip this work via `--no-write-fetch-head`. In that case, we do not care for the result of those lookups at all because we don't have to order writes to FETCH_HEAD in the first place. Skip this busywork in case we're not writing to FETCH_HEAD. The following benchmark performs a mirror-fetch in a repository with about two million references via `git fetch --prune --no-write-fetch-head +refs/*:refs/*`: Benchmark 1: HEAD~ Time (mean ± σ): 75.388 s ± 1.942 s [User: 71.103 s, System: 8.953 s] Range (min … max): 73.184 s … 76.845 s 3 runs Benchmark 2: HEAD Time (mean ± σ): 69.486 s ± 1.016 s [User: 65.941 s, System: 8.806 s] Range (min … max): 68.864 s … 70.659 s 3 runs Summary 'HEAD' ran 1.08 ± 0.03 times faster than 'HEAD~' Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4de6562 commit 8e55634

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

builtin/fetch.c

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
11431143
want_status <= FETCH_HEAD_IGNORE;
11441144
want_status++) {
11451145
for (rm = ref_map; rm; rm = rm->next) {
1146-
struct commit *commit = NULL;
11471146
struct ref *ref = NULL;
11481147

11491148
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
@@ -1154,21 +1153,34 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
11541153
}
11551154

11561155
/*
1157-
* References in "refs/tags/" are often going to point
1158-
* to annotated tags, which are not part of the
1159-
* commit-graph. We thus only try to look up refs in
1160-
* the graph which are not in that namespace to not
1161-
* regress performance in repositories with many
1162-
* annotated tags.
1156+
* When writing FETCH_HEAD we need to determine whether
1157+
* we already have the commit or not. If not, then the
1158+
* reference is not for merge and needs to be written
1159+
* to the reflog after other commits which we already
1160+
* have. We're not interested in this property though
1161+
* in case FETCH_HEAD is not to be updated, so we can
1162+
* skip the classification in that case.
11631163
*/
1164-
if (!starts_with(rm->name, "refs/tags/"))
1165-
commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
1166-
if (!commit) {
1167-
commit = lookup_commit_reference_gently(the_repository,
1168-
&rm->old_oid,
1169-
1);
1170-
if (!commit)
1171-
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
1164+
if (fetch_head->fp) {
1165+
struct commit *commit = NULL;
1166+
1167+
/*
1168+
* References in "refs/tags/" are often going to point
1169+
* to annotated tags, which are not part of the
1170+
* commit-graph. We thus only try to look up refs in
1171+
* the graph which are not in that namespace to not
1172+
* regress performance in repositories with many
1173+
* annotated tags.
1174+
*/
1175+
if (!starts_with(rm->name, "refs/tags/"))
1176+
commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
1177+
if (!commit) {
1178+
commit = lookup_commit_reference_gently(the_repository,
1179+
&rm->old_oid,
1180+
1);
1181+
if (!commit)
1182+
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
1183+
}
11721184
}
11731185

11741186
if (rm->fetch_head_status != want_status)

0 commit comments

Comments
 (0)