diff --git a/Documentation/git.txt b/Documentation/git.txt index 45b64a714..345366937 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -1000,9 +1000,20 @@ Unsetting the variable, or setting it to empty, "0" or Enables trace messages for all packets coming in or out of a given program. This can help with debugging object negotiation or other protocol issues. Tracing is turned off at a packet - starting with "PACK". + starting with "PACK" (but see 'GIT_TRACE_PACKFILE' below). See 'GIT_TRACE' for available trace output options. +'GIT_TRACE_PACKFILE':: + Enables tracing of packfiles sent or received by a + given program. Unlike other trace output, this trace is + verbatim: no headers, and no quoting of binary data. You almost + certainly want to direct into a file (e.g., + `GIT_TRACE_PACKFILE=/tmp/my.pack`) rather than displaying it on + the terminal or mixing it with other trace output. ++ +Note that this is currently only implemented for the client side +of clones and fetches. + 'GIT_TRACE_PERFORMANCE':: Enables performance related trace messages, e.g. total execution time of each Git command. diff --git a/pkt-line.c b/pkt-line.c index e75af023b..08a1427c0 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -4,16 +4,51 @@ char packet_buffer[LARGE_PACKET_MAX]; static const char *packet_trace_prefix = "git"; static struct trace_key trace_packet = TRACE_KEY_INIT(PACKET); +static struct trace_key trace_pack = TRACE_KEY_INIT(PACKFILE); void packet_trace_identity(const char *prog) { packet_trace_prefix = xstrdup(prog); } +static int packet_trace_pack(const char *buf, unsigned int len, int sideband) +{ + if (!sideband) { + trace_verbatim(&trace_pack, buf, len); + return 1; + } else if (len && *buf == '\1') { + trace_verbatim(&trace_pack, buf + 1, len - 1); + return 1; + } else { + /* it's another non-pack sideband */ + return 0; + } +} + static void packet_trace(const char *buf, unsigned int len, int write) { int i; struct strbuf out; + static int in_pack, sideband; + + if (!trace_want(&trace_packet) && !trace_want(&trace_pack)) + return; + + if (in_pack) { + if (packet_trace_pack(buf, len, sideband)) + return; + } else if (starts_with(buf, "PACK") || starts_with(buf, "\1PACK")) { + in_pack = 1; + sideband = *buf == '\1'; + packet_trace_pack(buf, len, sideband); + + /* + * Make a note in the human-readable trace that the pack data + * started. + */ + buf = "PACK ..."; + len = strlen(buf); + } if (!trace_want(&trace_packet)) return; @@ -24,21 +59,15 @@ static void packet_trace(const char *buf, unsigned int len, int write) strbuf_addf(&out, "packet: %12s%c ", packet_trace_prefix, write ? '>' : '<'); - if (starts_with(buf, "PACK") || starts_with(buf, "\1PACK")) { - strbuf_addstr(&out, "PACK ..."); - trace_disable(&trace_packet); - } - else { - /* XXX we should really handle printable utf8 */ - for (i = 0; i < len; i++) { - /* suppress newlines */ - if (buf[i] == '\n') - continue; - if (buf[i] >= 0x20 && buf[i] <= 0x7e) - strbuf_addch(&out, buf[i]); - else - strbuf_addf(&out, "\\%o", buf[i]); - } + /* XXX we should really handle printable utf8 */ + for (i = 0; i < len; i++) { + /* suppress newlines */ + if (buf[i] == '\n') + continue; + if (buf[i] >= 0x20 && buf[i] <= 0x7e) + strbuf_addch(&out, buf[i]); + else + strbuf_addf(&out, "\\%o", buf[i]); } strbuf_addch(&out, '\n'); diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index bfdaf7596..9b34f3c61 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -496,4 +496,11 @@ test_expect_success 'shallow clone locally' ' ( cd ddsstt && git fsck ) ' +test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' ' + rm -rf dst.git && + GIT_TRACE_PACKFILE=$PWD/tmp.pack git clone --no-local --bare src dst.git && + git init --bare replay.git && + git -C replay.git index-pack -v --stdin