Skip to content

Commit 6783fd3

Browse files
vdyegitster
authored andcommitted
builtin/diagnose.c: create 'git diagnose' builtin
Create a 'git diagnose' builtin to generate a standalone zip archive of repository diagnostics. The "diagnose" functionality was originally implemented for Scalar in aa5c79a (scalar: implement `scalar diagnose`, 2022-05-28). However, the diagnostics gathered are not specific to Scalar-cloned repositories and can be useful when diagnosing issues in any Git repository. Helped-by: Ævar Arnfjörð Bjarmason <[email protected]> Helped-by: Derrick Stolee <[email protected]> Signed-off-by: Victoria Dye <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 33cba72 commit 6783fd3

File tree

7 files changed

+143
-0
lines changed

7 files changed

+143
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
/git-cvsimport
5454
/git-cvsserver
5555
/git-daemon
56+
/git-diagnose
5657
/git-diff
5758
/git-diff-files
5859
/git-diff-index

Documentation/git-diagnose.txt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
git-diagnose(1)
2+
================
3+
4+
NAME
5+
----
6+
git-diagnose - Generate a zip archive of diagnostic information
7+
8+
SYNOPSIS
9+
--------
10+
[verse]
11+
'git diagnose' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
12+
13+
DESCRIPTION
14+
-----------
15+
Collects detailed information about the user's machine, Git client, and
16+
repository state and packages that information into a zip archive. The
17+
generated archive can then, for example, be shared with the Git mailing list to
18+
help debug an issue or serve as a reference for independent debugging.
19+
20+
The following information is captured in the archive:
21+
22+
* 'git version --build-options'
23+
* The path to the repository root
24+
* The available disk space on the filesystem
25+
* The name and size of each packfile, including those in alternate object
26+
stores
27+
* The total count of loose objects, as well as counts broken down by
28+
`.git/objects` subdirectory
29+
30+
This tool differs from linkgit:git-bugreport[1] in that it collects much more
31+
detailed information with a greater focus on reporting the size and data shape
32+
of repository contents.
33+
34+
OPTIONS
35+
-------
36+
-o <path>::
37+
--output-directory <path>::
38+
Place the resulting diagnostics archive in `<path>` instead of the
39+
current directory.
40+
41+
-s <format>::
42+
--suffix <format>::
43+
Specify an alternate suffix for the diagnostics archive name, to create
44+
a file named 'git-diagnostics-<formatted suffix>'. This should take the
45+
form of a strftime(3) format string; the current local time will be
46+
used.
47+
48+
GIT
49+
---
50+
Part of the linkgit:git[1] suite

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,7 @@ BUILTIN_OBJS += builtin/credential-cache.o
11541154
BUILTIN_OBJS += builtin/credential-store.o
11551155
BUILTIN_OBJS += builtin/credential.o
11561156
BUILTIN_OBJS += builtin/describe.o
1157+
BUILTIN_OBJS += builtin/diagnose.o
11571158
BUILTIN_OBJS += builtin/diff-files.o
11581159
BUILTIN_OBJS += builtin/diff-index.o
11591160
BUILTIN_OBJS += builtin/diff-tree.o

builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix);
144144
int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
145145
int cmd_credential_store(int argc, const char **argv, const char *prefix);
146146
int cmd_describe(int argc, const char **argv, const char *prefix);
147+
int cmd_diagnose(int argc, const char **argv, const char *prefix);
147148
int cmd_diff_files(int argc, const char **argv, const char *prefix);
148149
int cmd_diff_index(int argc, const char **argv, const char *prefix);
149150
int cmd_diff(int argc, const char **argv, const char *prefix);

builtin/diagnose.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "builtin.h"
2+
#include "parse-options.h"
3+
#include "diagnose.h"
4+
5+
static const char * const diagnose_usage[] = {
6+
N_("git diagnose [-o|--output-directory <path>] [-s|--suffix <format>]"),
7+
NULL
8+
};
9+
10+
int cmd_diagnose(int argc, const char **argv, const char *prefix)
11+
{
12+
struct strbuf zip_path = STRBUF_INIT;
13+
time_t now = time(NULL);
14+
struct tm tm;
15+
char *option_output = NULL;
16+
char *option_suffix = "%Y-%m-%d-%H%M";
17+
char *prefixed_filename;
18+
19+
const struct option diagnose_options[] = {
20+
OPT_STRING('o', "output-directory", &option_output, N_("path"),
21+
N_("specify a destination for the diagnostics archive")),
22+
OPT_STRING('s', "suffix", &option_suffix, N_("format"),
23+
N_("specify a strftime format suffix for the filename")),
24+
OPT_END()
25+
};
26+
27+
argc = parse_options(argc, argv, prefix, diagnose_options,
28+
diagnose_usage, 0);
29+
30+
/* Prepare the path to put the result */
31+
prefixed_filename = prefix_filename(prefix,
32+
option_output ? option_output : "");
33+
strbuf_addstr(&zip_path, prefixed_filename);
34+
strbuf_complete(&zip_path, '/');
35+
36+
strbuf_addstr(&zip_path, "git-diagnostics-");
37+
strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
38+
strbuf_addstr(&zip_path, ".zip");
39+
40+
switch (safe_create_leading_directories(zip_path.buf)) {
41+
case SCLD_OK:
42+
case SCLD_EXISTS:
43+
break;
44+
default:
45+
die_errno(_("could not create leading directories for '%s'"),
46+
zip_path.buf);
47+
}
48+
49+
/* Prepare diagnostics */
50+
if (create_diagnostics_archive(&zip_path, DIAGNOSE_STATS))
51+
die_errno(_("unable to create diagnostics archive %s"),
52+
zip_path.buf);
53+
54+
free(prefixed_filename);
55+
strbuf_release(&zip_path);
56+
return 0;
57+
}

git.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ static struct cmd_struct commands[] = {
522522
{ "credential-cache--daemon", cmd_credential_cache_daemon },
523523
{ "credential-store", cmd_credential_store },
524524
{ "describe", cmd_describe, RUN_SETUP },
525+
{ "diagnose", cmd_diagnose, RUN_SETUP_GENTLY },
525526
{ "diff", cmd_diff, NO_PARSEOPT },
526527
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
527528
{ "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },

t/t0092-diagnose.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/sh
2+
3+
test_description='git diagnose'
4+
5+
TEST_PASSES_SANITIZE_LEAK=true
6+
. ./test-lib.sh
7+
8+
test_expect_success UNZIP 'creates diagnostics zip archive' '
9+
test_when_finished rm -rf report &&
10+
11+
git diagnose -o report -s test >out &&
12+
grep "Available space" out &&
13+
14+
zip_path=report/git-diagnostics-test.zip &&
15+
test_path_is_file "$zip_path" &&
16+
17+
# Check zipped archive content
18+
"$GIT_UNZIP" -p "$zip_path" diagnostics.log >out &&
19+
test_file_not_empty out &&
20+
21+
"$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
22+
grep ".git/objects" out &&
23+
24+
"$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
25+
grep "^Total: [0-9][0-9]*" out &&
26+
27+
# Should not include .git directory contents by default
28+
! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
29+
grep "^Total: [0-9][0-9]*" out
30+
'
31+
32+
test_done

0 commit comments

Comments
 (0)