Browse Source

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
aa5c79a331 (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 <avarab@gmail.com>
Helped-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Victoria Dye 3 years ago committed by Junio C Hamano
parent
commit
6783fd3cef
  1. 1
      .gitignore
  2. 50
      Documentation/git-diagnose.txt
  3. 1
      Makefile
  4. 1
      builtin.h
  5. 57
      builtin/diagnose.c
  6. 1
      git.c
  7. 32
      t/t0092-diagnose.sh

1
.gitignore vendored

@ -53,6 +53,7 @@ @@ -53,6 +53,7 @@
/git-cvsimport
/git-cvsserver
/git-daemon
/git-diagnose
/git-diff
/git-diff-files
/git-diff-index

50
Documentation/git-diagnose.txt

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
git-diagnose(1)
================

NAME
----
git-diagnose - Generate a zip archive of diagnostic information

SYNOPSIS
--------
[verse]
'git diagnose' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]

DESCRIPTION
-----------
Collects detailed information about the user's machine, Git client, and
repository state and packages that information into a zip archive. The
generated archive can then, for example, be shared with the Git mailing list to
help debug an issue or serve as a reference for independent debugging.

The following information is captured in the archive:

* 'git version --build-options'
* The path to the repository root
* The available disk space on the filesystem
* The name and size of each packfile, including those in alternate object
stores
* The total count of loose objects, as well as counts broken down by
`.git/objects` subdirectory

This tool differs from linkgit:git-bugreport[1] in that it collects much more
detailed information with a greater focus on reporting the size and data shape
of repository contents.

OPTIONS
-------
-o <path>::
--output-directory <path>::
Place the resulting diagnostics archive in `<path>` instead of the
current directory.

-s <format>::
--suffix <format>::
Specify an alternate suffix for the diagnostics archive name, to create
a file named 'git-diagnostics-<formatted suffix>'. This should take the
form of a strftime(3) format string; the current local time will be
used.

GIT
---
Part of the linkgit:git[1] suite

1
Makefile

@ -1154,6 +1154,7 @@ BUILTIN_OBJS += builtin/credential-cache.o @@ -1154,6 +1154,7 @@ BUILTIN_OBJS += builtin/credential-cache.o
BUILTIN_OBJS += builtin/credential-store.o
BUILTIN_OBJS += builtin/credential.o
BUILTIN_OBJS += builtin/describe.o
BUILTIN_OBJS += builtin/diagnose.o
BUILTIN_OBJS += builtin/diff-files.o
BUILTIN_OBJS += builtin/diff-index.o
BUILTIN_OBJS += builtin/diff-tree.o

1
builtin.h

@ -144,6 +144,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix); @@ -144,6 +144,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix);
int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
int cmd_credential_store(int argc, const char **argv, const char *prefix);
int cmd_describe(int argc, const char **argv, const char *prefix);
int cmd_diagnose(int argc, const char **argv, const char *prefix);
int cmd_diff_files(int argc, const char **argv, const char *prefix);
int cmd_diff_index(int argc, const char **argv, const char *prefix);
int cmd_diff(int argc, const char **argv, const char *prefix);

57
builtin/diagnose.c

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
#include "builtin.h"
#include "parse-options.h"
#include "diagnose.h"

static const char * const diagnose_usage[] = {
N_("git diagnose [-o|--output-directory <path>] [-s|--suffix <format>]"),
NULL
};

int cmd_diagnose(int argc, const char **argv, const char *prefix)
{
struct strbuf zip_path = STRBUF_INIT;
time_t now = time(NULL);
struct tm tm;
char *option_output = NULL;
char *option_suffix = "%Y-%m-%d-%H%M";
char *prefixed_filename;

const struct option diagnose_options[] = {
OPT_STRING('o', "output-directory", &option_output, N_("path"),
N_("specify a destination for the diagnostics archive")),
OPT_STRING('s', "suffix", &option_suffix, N_("format"),
N_("specify a strftime format suffix for the filename")),
OPT_END()
};

argc = parse_options(argc, argv, prefix, diagnose_options,
diagnose_usage, 0);

/* Prepare the path to put the result */
prefixed_filename = prefix_filename(prefix,
option_output ? option_output : "");
strbuf_addstr(&zip_path, prefixed_filename);
strbuf_complete(&zip_path, '/');

strbuf_addstr(&zip_path, "git-diagnostics-");
strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
strbuf_addstr(&zip_path, ".zip");

switch (safe_create_leading_directories(zip_path.buf)) {
case SCLD_OK:
case SCLD_EXISTS:
break;
default:
die_errno(_("could not create leading directories for '%s'"),
zip_path.buf);
}

/* Prepare diagnostics */
if (create_diagnostics_archive(&zip_path, DIAGNOSE_STATS))
die_errno(_("unable to create diagnostics archive %s"),
zip_path.buf);

free(prefixed_filename);
strbuf_release(&zip_path);
return 0;
}

1
git.c

@ -522,6 +522,7 @@ static struct cmd_struct commands[] = { @@ -522,6 +522,7 @@ static struct cmd_struct commands[] = {
{ "credential-cache--daemon", cmd_credential_cache_daemon },
{ "credential-store", cmd_credential_store },
{ "describe", cmd_describe, RUN_SETUP },
{ "diagnose", cmd_diagnose, RUN_SETUP_GENTLY },
{ "diff", cmd_diff, NO_PARSEOPT },
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
{ "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },

32
t/t0092-diagnose.sh

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
#!/bin/sh

test_description='git diagnose'

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

test_expect_success UNZIP 'creates diagnostics zip archive' '
test_when_finished rm -rf report &&

git diagnose -o report -s test >out &&
grep "Available space" out &&

zip_path=report/git-diagnostics-test.zip &&
test_path_is_file "$zip_path" &&

# Check zipped archive content
"$GIT_UNZIP" -p "$zip_path" diagnostics.log >out &&
test_file_not_empty out &&

"$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
grep ".git/objects" out &&

"$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
grep "^Total: [0-9][0-9]*" out &&

# Should not include .git directory contents by default
! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
grep "^Total: [0-9][0-9]*" out
'

test_done
Loading…
Cancel
Save