diff --git a/send-pack.c b/send-pack.c index ae661e7e7401b3..123e0eebea2c3b 100644 --- a/send-pack.c +++ b/send-pack.c @@ -313,6 +313,49 @@ static int check_to_send_update(const struct ref *ref, const struct send_pack_ar } } +static void trace_push_ref_state(struct repository *r, + const struct ref *refs, + const struct send_pack_args *args) +{ + enum { REF_ABSENT = 1, REF_EXISTING = 2, REF_OTHER = 4 }; + unsigned int state = 0; + const char *value; + + if (!trace2_is_enabled()) + return; + + for (; refs; refs = refs->next) { + if (check_to_send_update(refs, args) == CHECK_REF_NO_PUSH) + continue; + if (refs->deletion || !starts_with(refs->name, "refs/heads/")) + state |= REF_OTHER; + else if (is_null_oid(&refs->old_oid)) + state |= REF_ABSENT; + else + state |= REF_EXISTING; + } + + switch (state) { + case 0: + value = "unknown"; + break; + case REF_ABSENT: + value = server_supports("explicit-haves") ? + "absent_explicit_haves" : "absent"; + break; + case REF_EXISTING: + value = "existing"; + break; + case REF_OTHER: + value = "other"; + break; + default: + value = "mixed"; + break; + } + trace2_data_string("send_pack", r, "ref_state", value); +} + /* * the beginning of the next line, or the end of buffer. * @@ -524,6 +567,7 @@ int send_pack(struct repository *r, goto out; } + trace_push_ref_state(r, remote_refs, args); repo_config_get_bool(r, "push.negotiate", &push_negotiate); if (push_negotiate) { trace2_region_enter("send_pack", "push_negotiate", r); diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 0b36f9919dee52..71b3731ba3158f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -193,6 +193,20 @@ grep_wrote () { grep 'write_pack_file/wrote.*"value":"'$1'"' $2 } +test_expect_success 'push Trace2 records selected remote ref state' ' + mk_empty testrepo && + GIT_TRACE2_EVENT="$PWD/testrepo/new.trace" git push \ + --receive-pack="git receive-pack --advertise-explicit-haves-for-testing" \ + testrepo $the_commit:refs/heads/topic && + test_grep "\"key\":\"ref_state\",\"value\":\"absent_explicit_haves\"" testrepo/new.trace && + GIT_TRACE2_EVENT="$PWD/testrepo/force.trace" git push --force testrepo $the_first_commit:refs/heads/topic && + test_grep "\"key\":\"ref_state\",\"value\":\"existing\"" testrepo/force.trace && + GIT_TRACE2_EVENT="$PWD/testrepo/noop.trace" git push testrepo $the_first_commit:refs/heads/topic && + test_grep "\"key\":\"ref_state\",\"value\":\"existing\"" testrepo/noop.trace && + GIT_TRACE2_EVENT="$PWD/testrepo/mixed.trace" git push testrepo $the_first_commit:refs/heads/topic $the_first_commit:refs/heads/another && + test_grep "\"key\":\"ref_state\",\"value\":\"mixed\"" testrepo/mixed.trace +' + test_expect_success 'push without negotiation' ' mk_empty testrepo && git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&