{"thread":{"id":"52442","subject":"[PATCH v4 00/15] add git-bugreport tool","startedAt":"2019-12-13T00:43:29Z","lastAt":"2020-02-24T02:56:05Z","messageCount":186,"participants":["Emily Shaffer","Junio C Hamano","Johannes Schindelin","Aaron Schrab","emilyshaffer@google.com","Jonathan Tan","Martin Ågren","Danh Doan","SZEDER Gábor","Eric Sunshine","Andreas Schwab"],"isPatch":true,"patchVersion":4,"patchTotal":15},"messages":[{"id":"388050","messageId":"20191213004312.169753-1-emilyshaffer@google.com","threadId":"52442","inReplyTo":null,"subject":"[PATCH v4 00/15] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:42:57Z","receivedAt":"2019-12-13T00:43:29Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"This topic branch depends on the patch mailed in\nlore.kernel.org/git/20191211233820.185153-1-emilyshaffer@google.com in order to\ndisplay scopes for configs gathered during \"bugreport: add config values from\nsafelist\".\n\nQuite a few changes since v3. I'll try to summarize the big picture\nstuff, plus highlight new changes and difference in patches inline in\nthe commit list. I'll also stick an interdiff since v3 at the bottom of\nthis cover letter.\n\nSome overall changes:\n- The entire command now exists in one file, bugreport.c, which is\n  compiled as a standalone.\n- static-ness of local functions has been cleaned up.\n- strbuf lifetime management has been cleaned up.\n- Mention of \"whitelist\" and \"blacklist\" has been changed to \"safelist\"\n  and \"blocklist\" while dealing with Git-approved bugreportable configs.\n  Thanks Dscho for pointing this out; \"safelist\" makes sense to me as\n  these are configs we have deemed safe for public inspection.\n- Inquiry into both Git's $SHELL_PATH and the user's $SHELL is new to\n  v4.\n- The 'man git bugreport' page which was lost from the script version of\n  git-bugreport has been recovered, as have the \"tests\" (which only test\n  whether it runs and doesn't crash).\n\n\nEmily Shaffer (15):\n  bugreport: add tool to generate debugging info\nMoved from library + builtin to a standalone git-bugreport binary.\n\n  help: move list_config_help to builtin/help\nResolves a circular dependency where using help.o required all builtins\nto exist. This also moves generation of config-list.h into its own\nscript (it was previously roommates with command-list.h).\n\nThe following 4 commits were previously a single commit which used\nrun-command.h to call different processes; this has been removed except\nfor the cURL version.\n\n  bugreport: gather git version and build info\nAdditionally capture the \"--build-info\" output from 'git version' where it\nwas not previously captured.\n\n  help: add shell-path to --build-options\nAdding $SHELL_PATH to 'git --version --build-options' gets it in the\nbugreport for free. (This is the shell Git uses, determined at build\ntime.)\n\n  bugreport: add uname info\nCapture uname from the library instead of invoking a different process.\n\n  bugreport: add glibc version\nCapture glibc version info from the library instead of invoking the\n'ldd' process.\n\n  bugreport: add curl version\nCapture the cURL version from git-http-fetch, and add a -V flag to that\nbinary for this purpose.\n\n\n  bugreport: include user interactive shell\nA new feature; check what $SHELL the user is using (at runtime)\n\n  bugreport: generate config safelist based on docs\nThis commit squashes in suggestions both from Johannes Schindelin and\nMartin Ågren, hopefully resulting in Asciidoc(tor) not showing the\nsafelist macros, and a more portable safelist generation script. It also\nputs the safelist, sorted, directly into a header instead of into a text\nfile, saving us a file read at runtime.\n\n  bugreport: add config values from safelist\nAt Dscho's suggestion, now we put these into a map (based on khash and\noidset.h's example) for constant-time lookup during the config parse.\n\n  bugreport: collect list of populated hooks\nOnly a minor change - now this works if 'git bugreport' is invoked\noutside of a Git repo.\n\n  bugreport: count loose objects\n  bugreport: add packed object summary\n  bugreport: list contents of $OBJDIR/info\nFor the above 3, the entire 'string_list' has been refactored out; now\nthe obj_info buffer is written to directly during the directory\ntraversal. Also paid more attention to when to free strbuf used for paths.\n\n  bugreport: summarize contents of alternates file\nRather than printing the contents of the alternates file, now the number\nof specified alternate stores are listed, and they are tested to check\nwhether they exist. This way we stop looking at user filepaths\n(sensitive) and start learning whether they have a broken alternate (new\nand useful info).\n\n .gitignore                              |   3 +\n Documentation/asciidoc.conf             |   8 +\n Documentation/asciidoctor-extensions.rb |   7 +\n Documentation/config/sendemail.txt      |  68 ++--\n Documentation/git-bugreport.txt         |  43 +++\n Documentation/git-http-fetch.txt        |   5 +\n Makefile                                |  31 +-\n bugreport.c                             | 434 ++++++++++++++++++++++++\n builtin/help.c                          |  86 +++++\n generate-bugreport-config-safelist.sh   |  22 ++\n generate-cmdlist.sh                     |  19 --\n generate-configlist.sh                  |  24 ++\n help.c                                  | 131 ++-----\n help.h                                  |   2 +-\n http-fetch.c                            |  13 +-\n t/t0091-bugreport.sh                    |  41 +++\n 16 files changed, 774 insertions(+), 163 deletions(-)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 generate-bugreport-config-safelist.sh\n create mode 100755 generate-configlist.sh\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 055a84c4a8..30935621d9 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -189,7 +189,9 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n+/bugreport-config-safelist.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\nindex 8fc4b67081..5d5359fcf9 100644\n--- a/Documentation/asciidoc.conf\n+++ b/Documentation/asciidoc.conf\n@@ -6,9 +6,13 @@\n #\n # Show Git link as: <command>(<section>); if section is defined, else just show\n # the command.\n+#\n+# The bugreport macro does nothing as far as rendering is\n+# concerned -- we just grep for it in the sources.\n \n [macros]\n (?su)[\\\\]?(?P<name>linkgit):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n+(?su)[\\\\]?(?P<name>bugreport):(?P<action>\\S*?)\\[(?P<attrlist>.*?)\\]=\n \n [attributes]\n asterisk=&#42;\n@@ -28,6 +32,8 @@ ifdef::backend-docbook[]\n {0#<citerefentry>}\n {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n {0#</citerefentry>}\n+[bugreport-inlinemacro]\n+{0#}\n endif::backend-docbook[]\n \n ifdef::backend-docbook[]\n@@ -94,4 +100,6 @@ ifdef::backend-xhtml11[]\n git-relative-html-prefix=\n [linkgit-inlinemacro]\n <a href=\"{git-relative-html-prefix}{target}.html\">{target}{0?({0})}</a>\n+[bugreport-inlinemacro]\n+<!-- -->\n endif::backend-xhtml11[]\ndiff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\nindex d906a00803..750bdff9af 100644\n--- a/Documentation/asciidoctor-extensions.rb\n+++ b/Documentation/asciidoctor-extensions.rb\n@@ -37,6 +37,10 @@ module Git\n           output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n         end\n         output\n+\n+    class BugReportProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n+      def process(parent, action, attrs)\n+        \"\"\n       end\n     end\n   end\n@@ -45,4 +49,7 @@ end\n Asciidoctor::Extensions.register do\n   inline_macro Git::Documentation::LinkGitProcessor, :linkgit\n   postprocessor Git::Documentation::DocumentPostProcessor\n+  # The bugreport macro does nothing as far as rendering is\n+  # concerned -- we just grep for it in the sources.\n+  inline_macro Git::Documentation::BugReportProcessor, :bugreport\n end\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 69f3e4f219..92f5082013 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -1,63 +1,63 @@\n-sendemail.identity:: // bugreport-exclude\n+sendemail.identity bugreport:exclude[x] ::\n \tA configuration identity. When given, causes values in the\n \t'sendemail.<identity>' subsection to take precedence over\n \tvalues in the 'sendemail' section. The default identity is\n \tthe value of `sendemail.identity`.\n \n-sendemail.smtpEncryption:: // bugreport-include\n+sendemail.smtpEncryption bugreport:include[x] ::\n \tSee linkgit:git-send-email[1] for description.  Note that this\n \tsetting is not subject to the 'identity' mechanism.\n \n-sendemail.smtpssl (deprecated):: // bugreport-exclude\n+sendemail.smtpssl (deprecated) bugreport:exclude[x] ::\n \tDeprecated alias for 'sendemail.smtpEncryption = ssl'.\n \n-sendemail.smtpsslcertpath:: // bugreport-exclude\n+sendemail.smtpsslcertpath bugreport:exclude[x] ::\n \tPath to ca-certificates (either a directory or a single file).\n \tSet it to an empty string to disable certificate verification.\n \n-sendemail.<identity>.*:: // bugreport-exclude\n+sendemail.<identity>.* bugreport:exclude[x] ::\n \tIdentity-specific versions of the 'sendemail.*' parameters\n \tfound below, taking precedence over those when this\n \tidentity is selected, through either the command-line or\n \t`sendemail.identity`.\n \n-sendemail.aliasesFile:: // bugreport-exclude\n-sendemail.aliasFileType:: // bugreport-exclude\n-sendemail.annotate:: // bugreport-include\n-sendemail.bcc:: // bugreport-include\n-sendemail.cc:: // bugreport-include\n-sendemail.ccCmd:: // bugreport-include\n-sendemail.chainReplyTo:: // bugreport-include\n-sendemail.confirm:: // bugreport-include\n-sendemail.envelopeSender:: // bugreport-include\n-sendemail.from:: // bugreport-include\n-sendemail.multiEdit:: // bugreport-include\n-sendemail.signedoffbycc:: // bugreport-include\n-sendemail.smtpPass:: // bugreport-exclude\n-sendemail.suppresscc:: // bugreport-include\n-sendemail.suppressFrom:: // bugreport-include\n-sendemail.to:: // bugreport-include\n-sendemail.tocmd:: // bugreport-include\n-sendemail.smtpDomain:: // bugreport-include\n-sendemail.smtpServer:: // bugreport-include\n-sendemail.smtpServerPort:: // bugreport-include\n-sendemail.smtpServerOption:: // bugreport-include\n-sendemail.smtpUser:: // bugreport-exclude\n-sendemail.thread:: // bugreport-include\n-sendemail.transferEncoding:: // bugreport-include\n-sendemail.validate:: // bugreport-include\n-sendemail.xmailer:: // bugreport-include\n+sendemail.aliasesFile bugreport:exclude[x] ::\n+sendemail.aliasFileType bugreport:exclude[x] ::\n+sendemail.annotate bugreport:include[x] ::\n+sendemail.bcc bugreport:include[x] ::\n+sendemail.cc bugreport:include[x] ::\n+sendemail.ccCmd bugreport:include[x] ::\n+sendemail.chainReplyTo bugreport:include[x] ::\n+sendemail.confirm bugreport:include[x] ::\n+sendemail.envelopeSender bugreport:include[x] ::\n+sendemail.from bugreport:include[x] ::\n+sendemail.multiEdit bugreport:include[x] ::\n+sendemail.signedoffbycc bugreport:include[x] ::\n+sendemail.smtpPass bugreport:exclude[x] ::\n+sendemail.suppresscc bugreport:include[x] ::\n+sendemail.suppressFrom bugreport:include[x] ::\n+sendemail.to bugreport:include[x] ::\n+sendemail.tocmd bugreport:include[x] ::\n+sendemail.smtpDomain bugreport:include[x] ::\n+sendemail.smtpServer bugreport:include[x] ::\n+sendemail.smtpServerPort bugreport:include[x] ::\n+sendemail.smtpServerOption bugreport:include[x] ::\n+sendemail.smtpUser bugreport:exclude[x] ::\n+sendemail.thread bugreport:include[x] ::\n+sendemail.transferEncoding bugreport:include[x] ::\n+sendemail.validate bugreport:include[x] ::\n+sendemail.xmailer bugreport:include[x] ::\n \tSee linkgit:git-send-email[1] for description.\n \n-sendemail.signedoffcc (deprecated):: // bugreport-exclude\n+sendemail.signedoffcc (deprecated) bugreport:exclude[x] ::\n \tDeprecated alias for `sendemail.signedoffbycc`.\n \n-sendemail.smtpBatchSize:: // bugreport-include\n+sendemail.smtpBatchSize bugreport:include[x] ::\n \tNumber of messages to be sent per connection, after that a relogin\n \twill happen.  If the value is 0 or undefined, send all messages in\n \tone connection.\n \tSee also the `--batch-size` option of linkgit:git-send-email[1].\n \n-sendemail.smtpReloginDelay:: // bugreport-include\n+sendemail.smtpReloginDelay bugreport:include[x] ::\n \tSeconds wait before reconnecting to smtp server.\n \tSee also the `--relogin-delay` option of linkgit:git-send-email[1].\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..75f0c80acf\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,43 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [-o | --output <path>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+The following information is captured automatically:\n+\n+ - Git version (`git version --build-options`)\n+ - Machine information (`uname -a`)\n+ - Versions of various dependencies\n+ - Git config contents (`git config --show-origin --list`)\n+ - The names of all configured git-hooks in `.git/hooks/`\n+\n+OPTIONS\n+-------\n+-o [<path>]::\n+--output [<path>]::\n+\tPlace the resulting bug report file in <path> instead of the root of the\n+\tGit repository.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt\nindex 666b042679..2894c5e82b 100644\n--- a/Documentation/git-http-fetch.txt\n+++ b/Documentation/git-http-fetch.txt\n@@ -10,6 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [--stdin] <commit> <url>\n+'git http-fetch' [-V]\n \n DESCRIPTION\n -----------\n@@ -30,6 +31,10 @@ commit-id::\n -v::\n \tReport what is downloaded.\n \n+-V::\n+\tReport information about the version of git-http-fetch, including the\n+\tversions of its dependencies.\n+\n -w <filename>::\n         Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on\n         the local end after the transfer is complete.\ndiff --git a/Makefile b/Makefile\nindex 6e361eed64..76dc51e2b1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -634,10 +634,6 @@ SCRIPT_PYTHON += git-p4.py\n SCRIPT_SH_GEN = $(patsubst %.sh,%,$(SCRIPT_SH))\n SCRIPT_PERL_GEN = $(patsubst %.perl,%,$(SCRIPT_PERL))\n SCRIPT_PYTHON_GEN = $(patsubst %.py,%,$(SCRIPT_PYTHON))\n-SCRIPT_DEPENDENCIES = git-bugreport-config-whitelist\n-\n-$(SCRIPT_DEPENDENCIES): Documentation/config/*.txt\n-\tsh bugreport-generate-config-whitelist.sh\n \n # Individual rules to allow e.g.\n # \"make -C ../.. SCRIPT_PERL=contrib/foo/bar.perl build-perl-script\"\n@@ -662,13 +658,10 @@ clean-perl-script:\n \t$(RM) $(SCRIPT_PERL_GEN)\n clean-python-script:\n \t$(RM) $(SCRIPT_PYTHON_GEN)\n-clean-script-dependencies:\n-\t$(RM) $(SCRIPT_DEPENDENCIES)\n \n SCRIPTS = $(SCRIPT_SH_GEN) \\\n \t  $(SCRIPT_PERL_GEN) \\\n \t  $(SCRIPT_PYTHON_GEN) \\\n-\t  $(SCRIPT_DEPENDENCIES) \\\n \t  git-instaweb\n \n ETAGS_TARGET = TAGS\n@@ -688,6 +681,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -821,7 +815,9 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n+GENERATED_H += bugreport-config-safelist.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n \t$(FIND) . \\\n@@ -846,7 +842,6 @@ LIB_OBJS += bisect.o\n LIB_OBJS += blame.o\n LIB_OBJS += blob.o\n LIB_OBJS += branch.o\n-LIB_OBJS += bugreport.o\n LIB_OBJS += bulk-checkin.o\n LIB_OBJS += bundle.o\n LIB_OBJS += cache-tree.o\n@@ -1049,7 +1044,6 @@ BUILTIN_OBJS += builtin/archive.o\n BUILTIN_OBJS += builtin/bisect--helper.o\n BUILTIN_OBJS += builtin/blame.o\n BUILTIN_OBJS += builtin/branch.o\n-BUILTIN_OBJS += builtin/bugreport.o\n BUILTIN_OBJS += builtin/bundle.o\n BUILTIN_OBJS += builtin/cat-file.o\n BUILTIN_OBJS += builtin/check-attr.o\n@@ -2135,7 +2129,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2155,6 +2149,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2162,6 +2162,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\tcommand-list.txt >$@+ && mv $@+ $@\n \n+bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n+\n+bugreport-config-safelist.h: Documentation/config/*.txt\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n@@ -2457,6 +2463,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\n@@ -2788,7 +2798,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-GEN_HDRS := command-list.h unicode-width.h\n+GEN_HDRS := config-list.h command-list.h unicode-width.h bugreport-config-safelist.h\n EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n@@ -2811,7 +2821,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -3114,7 +3124,9 @@ clean: profile-clean coverage-clean cocciclean\n \t$(RM) $(HCC)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo\n+\t$(RM) config-list.h command-list.h bugreport-config-safelist.h\n+\t$(RM) $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/bugreport-generate-config-whitelist.sh b/bugreport-generate-config-whitelist.sh\ndeleted file mode 100755\nindex ca6b232024..0000000000\n--- a/bugreport-generate-config-whitelist.sh\n+++ /dev/null\n@@ -1,4 +0,0 @@\n-#!/bin/sh\n-\n-grep -RhPo \".*(?=:: \\/\\/ bugreport-include)\" Documentation/config \\\n-  >git-bugreport-config-whitelist\ndiff --git a/bugreport.c b/bugreport.c\nindex a7bdc72b7f..d2a3fb1f67 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,114 +1,128 @@\n #include \"cache.h\"\n-\n-#include \"bugreport.h\"\n-#include \"config.h\"\n-#include \"exec-cmd.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n #include \"help.h\"\n+#include <gnu/libc-version.h>\n #include \"run-command.h\"\n-#include \"strbuf.h\"\n-#include \"string-list.h\"\n-#include \"version.h\"\n-\n-#include \"dirent.h\"\n-\n-/**\n- * A sorted list of config options which we will add to the bugreport. Managed\n- * by 'gather_whitelist(...)'.\n- */\n-struct string_list whitelist = STRING_LIST_INIT_DUP;\n-struct strbuf configs_and_values = STRBUF_INIT;\n-\n-// git version --build-options\n-// uname -a\n-// curl-config --version\n-// ldd --version\n-// echo $SHELL\n-void get_system_info(struct strbuf *sys_info)\n+#include \"config.h\"\n+#include \"bugreport-config-safelist.h\"\n+#include \"khash.h\"\n+#include \"run-command.h\"\n+\n+static void get_http_version_info(struct strbuf *http_info)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tstruct strbuf std_out = STRBUF_INIT;\n \n-\tstrbuf_reset(sys_info);\n+\targv_array_push(&cp.args, \"git\");\n+\targv_array_push(&cp.args, \"http-fetch\");\n+\targv_array_push(&cp.args, \"-V\");\n+\tif (capture_command(&cp, http_info, 0))\n+\t    strbuf_addstr(http_info, \"'git-http-fetch -V' not supported\\n\");\n+}\n \n-\t// get git version from native cmd\n-\tstrbuf_addstr(sys_info, \"git version: \");\n-\tstrbuf_addstr(sys_info, git_version_string);\n-\tstrbuf_complete_line(sys_info);\n+KHASH_INIT(cfg_set, const char*, int, 0, kh_str_hash_func, kh_str_hash_equal);\n \n-\t// system call for other version info\n-\targv_array_push(&cp.args, \"uname\");\n-\targv_array_push(&cp.args, \"-a\");\n-\tcapture_command(&cp, &std_out, 0);\n+struct cfgset {\n+\tkh_cfg_set_t set;\n+};\n \n-\tstrbuf_addstr(sys_info, \"uname -a: \");\n-\tstrbuf_addbuf(sys_info, &std_out);\n-\tstrbuf_complete_line(sys_info);\n-\n-\targv_array_clear(&cp.args);\n-\tstrbuf_reset(&std_out);\n+struct cfgset safelist;\n \n+static void cfgset_init(struct cfgset *set, size_t initial_size)\n+{\n+\tmemset(&set->set, 0, sizeof(set->set));\n+\tif (initial_size)\n+\t\tkh_resize_cfg_set(&set->set, initial_size);\n+}\n \n-\targv_array_push(&cp.args, \"curl-config\");\n-\targv_array_push(&cp.args, \"--version\");\n-\tcapture_command(&cp, &std_out, 0);\n+static int cfgset_insert(struct cfgset *set, const char *cfg_key)\n+{\n+\tint added;\n+\tkh_put_cfg_set(&set->set, cfg_key, &added);\n+\tprintf(\"ESS: added %s\\n\", cfg_key);\n+\treturn !added;\n+}\n \n-\tstrbuf_addstr(sys_info, \"curl-config --version: \");\n-\tstrbuf_addbuf(sys_info, &std_out);\n-\tstrbuf_complete_line(sys_info);\n+static int cfgset_contains(struct cfgset *set, const char *cfg_key)\n+{\n+\tkhiter_t pos = kh_get_cfg_set(&set->set, cfg_key);\n+\treturn pos != kh_end(&set->set);\n+}\n \n-\targv_array_clear(&cp.args);\n-\tstrbuf_reset(&std_out);\n+static void cfgset_clear(struct cfgset *set)\n+{\n+\tkh_release_cfg_set(&set->set);\n+\tcfgset_init(set, 0);\n+}\n \n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\tstruct strbuf version_info = STRBUF_INIT;\n+\tstruct utsname uname_info;\n \n-\targv_array_push(&cp.args, \"ldd\");\n-\targv_array_push(&cp.args, \"--version\");\n-\tcapture_command(&cp, &std_out, 0);\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, \"git version:\\n\");\n+\tlist_version_info(&version_info, 1);\n+\tstrbuf_addbuf(sys_info, &version_info);\n+\tstrbuf_complete_line(sys_info);\n \n-\tstrbuf_addstr(sys_info, \"ldd --version: \");\n-\tstrbuf_addbuf(sys_info, &std_out);\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname -a: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, \"uname() failed with code %d\\n\", errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.nodename,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, \"glibc version: \");\n+\tstrbuf_addstr(sys_info, gnu_get_libc_version());\n \tstrbuf_complete_line(sys_info);\n \n-\targv_array_clear(&cp.args);\n-\tstrbuf_reset(&std_out);\n-}\n+\tstrbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n+\t\t    getenv(\"SHELL\"));\n \n-void gather_whitelist(struct strbuf *path)\n-{\n-\tstruct strbuf tmp = STRBUF_INIT;\n-\tstrbuf_read_file(&tmp, path->buf, 0);\n-\tstring_list_init(&whitelist, 1);\n-\tstring_list_split(&whitelist, tmp.buf, '\\n', -1);\n-\tstring_list_sort(&whitelist);\n+\tstrbuf_addstr(sys_info, \"git-http-fetch -V:\\n\");\n+\tget_http_version_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n-int git_config_bugreport(const char *var, const char *value, void *cb)\n+static void gather_safelist()\n {\n-\tif (string_list_has_string(&whitelist, var)) {\n-\t\tstrbuf_addf(&configs_and_values,\n-\t\t\t    \"%s : %s\\n\",\n-\t\t\t    var, value);\n-\t}\n+\tint index;\n+\tint safelist_len = sizeof(bugreport_config_safelist) / sizeof(const char *);\n+\tcfgset_init(&safelist, safelist_len);\n+\tfor (index = 0; index < safelist_len; index++)\n+\t\tcfgset_insert(&safelist, bugreport_config_safelist[index]);\n \n-\treturn 0;\n }\n \n-void get_whitelisted_config(struct strbuf *config_info)\n+static int git_config_bugreport(const char *var, const char *value, void *cb)\n {\n-\tstruct strbuf path = STRBUF_INIT;\n+\tstruct strbuf *config_info = (struct strbuf *)cb;\n \n-\tstrbuf_addstr(&path, git_exec_path());\n-\tstrbuf_addstr(&path, \"/git-bugreport-config-whitelist\");\n+\tif (cfgset_contains(&safelist, var))\n+\t\tstrbuf_addf(config_info,\n+\t\t\t    \"%s (%s) : %s\\n\",\n+\t\t\t    var, config_scope_to_string(current_config_scope()),\n+\t\t\t    value);\n \n-\tgather_whitelist(&path);\n-\tstrbuf_init(&configs_and_values, whitelist.nr);\n-\n-\tgit_config(git_config_bugreport, NULL);\n+\treturn 0;\n+}\n \n-\tstrbuf_reset(config_info);\n-\tstrbuf_addbuf(config_info, &configs_and_values);\n+static void get_safelisted_config(struct strbuf *config_info)\n+{\n+\tgather_safelist();\n+\tgit_config(git_config_bugreport, config_info);\n+\tcfgset_clear(&safelist);\n }\n \n-void get_populated_hooks(struct strbuf *hook_info)\n+static void get_populated_hooks(struct strbuf *hook_info)\n {\n \t/*\n \t * Doesn't look like there is a list of all possible hooks; so below is\n@@ -139,8 +153,15 @@ void get_populated_hooks(struct strbuf *hook_info)\n \t\t\t    \"post-index-changex\";\n \tstruct string_list hooks_list = STRING_LIST_INIT_DUP;\n \tstruct string_list_item *iter = NULL;\n+\tint nongit_ok;\n+\n+\tsetup_git_directory_gently(&nongit_ok);\n \n-\tstrbuf_reset(hook_info);\n+\tif (nongit_ok) {\n+\t\tstrbuf_addstr(hook_info,\n+\t\t\t\"not run from a git repository - no hooks to show\\n\");\n+\t\treturn;\n+\t}\n \n \tstring_list_split(&hooks_list, hooks, ',', -1);\n \n@@ -152,163 +173,262 @@ void get_populated_hooks(struct strbuf *hook_info)\n \t}\n }\n \n-/**\n- * Fill 'contents' with the contents of the dir at 'dirpath'.\n- * If 'filter' is nonzero, the contents are filtered on d_type as 'type' - see\n- * 'man readdir'. opendir() doesn't take string length as an arg, so don't\n- * bother passing it in.\n- */\n-void list_contents_of_dir(struct string_list *contents, struct strbuf *dirpath,\n-\t\t\t  int filter, unsigned char type)\n+static int is_hex(const char *string, size_t count)\n {\n-\tstruct dirent *dir = NULL;\n-\tDIR *dh = NULL;\n-\n-\tdh = opendir(dirpath->buf);\n-\twhile (dh && (dir = readdir(dh))) {\n-\t\tif (!filter || type == dir->d_type) {\n-\t\t\tstring_list_append(contents, dir->d_name);\n-\t\t}\n+\tfor (; count; string++, count--) {\n+\t\tif (!isxdigit(*string))\n+\t\t\treturn 0;\n \t}\n+\treturn 1;\n }\n \n-/**\n- * Fills 'contents' with a list of all directories within the provided\n- * directory, recursing into each directory.\n- */\n-void list_contents_of_dir_recursively(struct string_list *contents,\n-\t\t\t\t      struct strbuf *dirpath)\n-{\n-\tstruct string_list current_contents = STRING_LIST_INIT_DUP;\n-\tstruct string_list current_subdirs = STRING_LIST_INIT_DUP;\n-\tstruct string_list_item *it;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\n-\tlist_contents_of_dir(&current_contents, dirpath, 0, 0);\n-\tfor_each_string_list_item(it, &current_contents) {\n-\t\tstrbuf_reset(&buf);\n-\t\tstrbuf_addbuf(&buf, dirpath);\n-\t\tstrbuf_complete(&buf, '/');\n-\t\tstrbuf_addstr(&buf, it->string);\n-\n-\t\tstring_list_append(contents, buf.buf);\n-\t}\n+static void get_loose_object_summary(struct strbuf *obj_info) {\n+\tstruct dirent *d = NULL;\n+\tDIR *dir, *subdir = NULL;\n+\tsize_t dir_len;\n+\tstruct strbuf dirpath = STRBUF_INIT;\n \n-\tlist_contents_of_dir(&current_subdirs, dirpath, 1, DT_DIR);\n-\tfor_each_string_list_item(it, &current_subdirs) {\n-\t\tif (strcmp(it->string, \".\") == 0\n-\t\t    || strcmp(it->string, \"..\") == 0)\n-\t\t\tcontinue;\n-\t\tstrbuf_reset(&buf);\n-\t\tstrbuf_addbuf(&buf, dirpath);\n-\t\tstrbuf_complete(&buf, '/');\n-\t\tstrbuf_addstr(&buf, it->string);\n+\tstrbuf_addstr(&dirpath, get_object_directory());\n+\tstrbuf_complete(&dirpath, '/');\n \n-\t\tlist_contents_of_dir_recursively(contents, &buf);\n+\tdir = opendir(dirpath.buf);\n+\tif (!dir) {\n+\t\tstrbuf_addf(obj_info, \"could not open object directory '%s'\\n\",\n+\t\t\t    dirpath.buf);\n+\t\tstrbuf_release(&dirpath);\n+\t\treturn;\n \t}\n-}\n \n-void get_object_counts(struct strbuf *obj_info)\n-{\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tstruct strbuf std_out = STRBUF_INIT;\n-\n-\targv_array_push(&cp.args, \"count-objects\");\n-\targv_array_push(&cp.args, \"-vH\");\n-\tcp.git_cmd = 1;\n-\tcapture_command(&cp, &std_out, 0);\n+\tdir_len = dirpath.len;\n \n-\tstrbuf_reset(obj_info);\n-\tstrbuf_addstr(obj_info, \"git-count-objects -vH:\\n\");\n-\tstrbuf_addbuf(obj_info, &std_out);\n-}\n+\twhile ((d = readdir(dir))) {\n+\t\tint object_count = 0;\n+\t\tchar subdir_name[3];\n \n-void get_loose_object_summary(struct strbuf *obj_info)\n-{\n-\tstruct strbuf dirpath = STRBUF_INIT;\n-\tstruct string_list subdirs = STRING_LIST_INIT_DUP;\n-\tstruct string_list_item *subdir;\n-\n-\tstrbuf_reset(obj_info);\n+\t\tif (d->d_type != DT_DIR)\n+\t\t\tcontinue;\n \n-\tstrbuf_addstr(&dirpath, get_object_directory());\n-\tstrbuf_complete(&dirpath, '/');\n+\t\tif ((strlen(d->d_name) != 2) || (!is_hex(d->d_name, 2)))\n+\t\t\tcontinue;\n \n-\tlist_contents_of_dir(&subdirs, &dirpath, 1, DT_DIR);\n+\t\t/* copy directory name + \\0 */\n+\t\tmemcpy(subdir_name, d->d_name, 3);\n \n-\tfor_each_string_list_item(subdir, &subdirs)\n-\t{\n-\t\tstruct strbuf subdir_buf = STRBUF_INIT;\n-\t\tstruct string_list objects = STRING_LIST_INIT_DUP;\n+\t\tstrbuf_setlen(&dirpath, dir_len);\n+\t\tstrbuf_addstr(&dirpath, d->d_name);\n \n-\t\t/*\n-\t\t * Only interested in loose objects - so dirs named with the\n-\t\t * first byte of the object ID\n-\t\t */\n-\t\tif (strlen(subdir->string) != 2 || !strcmp(subdir->string, \"..\"))\n+\t\tsubdir = opendir(dirpath.buf);\n+\t\tif (!subdir)\n \t\t\tcontinue;\n+\t\twhile ((d = readdir(subdir)))\n+\t\t\tif (d->d_type == DT_REG)\n+\t\t\t\tobject_count++;\n+\n+\t\tclosedir(subdir);\n \n-\t\tstrbuf_addbuf(&subdir_buf, &dirpath);\n-\t\tstrbuf_addstr(&subdir_buf, subdir->string);\n-\t\tlist_contents_of_dir(&objects, &subdir_buf, 0, 0);\n-\t\tstrbuf_addf(obj_info, \"%s: %d objects\\n\", subdir->string,\n-\t\t\t    objects.nr);\n+\t\tstrbuf_addf(obj_info, \"%s: %d\\n\", subdir_name, object_count);\n \t}\n+\n+\n+\tclosedir(dir);\n+\tstrbuf_release(&dirpath);\n }\n \n-void get_packed_object_summary(struct strbuf *obj_info)\n+static void get_packed_object_summary(struct strbuf *obj_info)\n {\n \tstruct strbuf dirpath = STRBUF_INIT;\n-\tstruct string_list contents = STRING_LIST_INIT_DUP;\n-\tstruct string_list_item *entry;\n-\n-\tstrbuf_reset(obj_info);\n+\tstruct dirent *d;\n+\tDIR *dir = NULL;\n \n \tstrbuf_addstr(&dirpath, get_object_directory());\n \tstrbuf_complete(&dirpath, '/');\n \tstrbuf_addstr(&dirpath, \"pack/\");\n-\tlist_contents_of_dir(&contents, &dirpath, 0, 0);\n \n-\t// list full contents of $GIT_OBJECT_DIRECTORY/pack/\n-\tfor_each_string_list_item(entry, &contents) {\n+\tdir = opendir(dirpath.buf);\n+\tif (!dir) {\n+\t\tstrbuf_addf(obj_info, \"could not open packed object directory '%s'\\n\",\n+\t\t\t    dirpath.buf);\n+\t\tstrbuf_release(&dirpath);\n+\t\treturn;\n+\t}\n+\n+\twhile ((d = readdir(dir))) {\n \t\tstrbuf_addbuf(obj_info, &dirpath);\n-\t\tstrbuf_addstr(obj_info, entry->string);\n+\t\tstrbuf_addstr(obj_info, d->d_name);\n \t\tstrbuf_complete_line(obj_info);\n \t}\n+\n+\tclosedir(dir);\n+\tstrbuf_release(&dirpath);\n }\n \n-void get_object_info_summary(struct strbuf *obj_info)\n+static void list_contents_of_dir_recursively(struct strbuf *contents,\n+\t\t\t\t      \t     struct strbuf *dirpath)\n {\n-\t// strbuf += GITDIR/info/:\n-\t// recursively list contents of $GIT_OBJECT_DIRECTORY/info\n-\tstruct strbuf dirpath = STRBUF_INIT;\n-\tstruct string_list contents = STRING_LIST_INIT_DUP;\n-\tstruct string_list_item *entry;\n+\tstruct dirent *d;\n+\tDIR *dir;\n+\tsize_t path_len;\n \n-\tstrbuf_reset(obj_info);\n+\tdir = opendir(dirpath->buf);\n+\tif (!dir)\n+\t\treturn;\n+\n+\tstrbuf_complete(dirpath, '/');\n+\tpath_len = dirpath->len;\n+\n+\twhile ((d = readdir(dir))) {\n+\t\tif (!strcmp(d->d_name, \".\") || !strcmp(d->d_name, \"..\"))\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_addbuf(contents, dirpath);\n+\t\tstrbuf_addstr(contents, d->d_name);\n+\t\tstrbuf_complete_line(contents);\n+\n+\t\tif (d->d_type == DT_DIR) {\n+\t\t\tstrbuf_addstr(dirpath, d->d_name);\n+\t\t\tlist_contents_of_dir_recursively(contents, dirpath);\n+\t\t}\n+\t\tstrbuf_setlen(dirpath, path_len);\n+\t}\n+\n+\tclosedir(dir);\n+}\n+\n+static void get_object_info_summary(struct strbuf *obj_info)\n+{\n+\tstruct strbuf dirpath = STRBUF_INIT;\n \n \tstrbuf_addstr(&dirpath, get_object_directory());\n \tstrbuf_complete(&dirpath, '/');\n \tstrbuf_addstr(&dirpath, \"info/\");\n \n-\tlist_contents_of_dir_recursively(&contents, &dirpath);\n+\tlist_contents_of_dir_recursively(obj_info, &dirpath);\n \n-\tfor_each_string_list_item(entry, &contents) {\n-\t\tstrbuf_addstr(obj_info, entry->string);\n-\t\tstrbuf_complete_line(obj_info);\n-\t}\n+\tstrbuf_release(&dirpath);\n }\n \n-void get_alternates_file(struct strbuf *alternates_info)\n+static void get_alternates_summary(struct strbuf *alternates_info)\n {\n \tstruct strbuf alternates_path = STRBUF_INIT;\n+\tstruct strbuf alternate = STRBUF_INIT;\n+\tFILE *file;\n+\tsize_t exists = 0, broken = 0;\n \n \tstrbuf_addstr(&alternates_path, get_object_directory());\n \tstrbuf_complete(&alternates_path, '/');\n \tstrbuf_addstr(&alternates_path, \"info/alternates\");\n \n-\tstrbuf_reset(alternates_info);\n-\tstrbuf_addbuf(alternates_info, &alternates_path);\n-\tstrbuf_complete_line(alternates_info);\n-\tstrbuf_read_file(alternates_info, alternates_path.buf, 0);\n+\tfile = fopen(alternates_path.buf, \"r\");\n+\tif (!file) {\n+\t\tstrbuf_addstr(alternates_info, \"No alternates file found.\\n\");\n+\t\tstrbuf_release(&alternates_path);\n+\t\treturn;\n+\t}\n+\n+\twhile (strbuf_getline(&alternate, file) != EOF) {\n+\t\tif (!access(alternate.buf, F_OK))\n+\t\t\texists++;\n+\t\telse\n+\t\t\tbroken++;\n+\t}\n+\n+\tstrbuf_addf(alternates_info,\n+\t\t    \"%zd alternates found (%zd working, %zd broken)\\n\",\n+\t\t    exists + broken,\n+\t\t    exists,\n+\t\t    broken);\n+\n+\tfclose(file);\n+\tstrbuf_release(&alternate);\n+\tstrbuf_release(&alternates_path);\n+}\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output <file>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to send.\\n\");\n+\n+\tstrbuf_addstr(template, template_text);\n+\treturn 0;\n+}\n+\n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tFILE *report;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"\", bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\tif (option_output) {\n+\t\tstrbuf_addstr(&report_path, option_output);\n+\t\tstrbuf_complete(&report_path, '/');\n+\t}\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, \"%F\", gmtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\n+\tget_bug_template(&buffer);\n+\n+\tget_header(&buffer, \"System Info\");\n+\tget_system_info(&buffer);\n+\n+\tget_header(&buffer, \"Safelisted Config Info\");\n+\tget_safelisted_config(&buffer);\n+\n+\tget_header(&buffer, \"Configured Hooks\");\n+\tget_populated_hooks(&buffer);\n+\n+\tget_header(&buffer, \"Loose Object Counts\");\n+\tget_loose_object_summary(&buffer);\n+\n+\tget_header(&buffer, \"Packed Object Summary\");\n+\tget_packed_object_summary(&buffer);\n+\n+\tget_header(&buffer, \"Object Info Summary\");\n+\tget_object_info_summary(&buffer);\n+\n+\tget_header(&buffer, \"Alternates\");\n+\tget_alternates_summary(&buffer);\n+\n+\treport = fopen_for_writing(report_path.buf);\n+\tstrbuf_write(&buffer, report);\n+\tfclose(report);\n+\n+\tlaunch_editor(report_path.buf, NULL, NULL);\n+\treturn 0;\n }\ndiff --git a/bugreport.h b/bugreport.h\ndeleted file mode 100644\nindex 74d1f79960..0000000000\n--- a/bugreport.h\n+++ /dev/null\n@@ -1,44 +0,0 @@\n-#include \"strbuf.h\"\n-\n-/**\n- * Adds the Git version, `uname -a`, and `curl-config --version` to sys_info.\n- * The previous contents of sys_info will be discarded.\n- */\n-void get_system_info(struct strbuf *sys_info);\n-\n-/**\n- * Adds the values of the config items listed in\n- * 'git-bugreport-config-whitelist' to config_info. The previous contents of\n- * config_info will be discarded.\n- */\n-void get_whitelisted_config(struct strbuf *sys_info);\n-\n-/**\n- * Adds the paths to all configured hooks (but not their contents). The previous\n- * contents of hook_info will be discarded.\n- */\n-void get_populated_hooks(struct strbuf *hook_info);\n-\n-/**\n- * Adds the output of `git count-object -vH`. The previous contents of hook_info\n- * will be discarded.\n- */\n-void get_loose_object_summary(struct strbuf *obj_info);\n-\n-/**\n- * Adds a list of the contents of '.git/objects/pack'. The previous contents of\n- * hook_info will be discarded.\n- */\n-void get_packed_object_summary(struct strbuf *obj_info);\n-\n-/**\n- * Adds a list of all contents (recursively) of '.git/objects/info'. The\n- * previous contents of hook_info will be discarded.\n- */\n-void get_object_info_summary(struct strbuf *obj_info);\n-\n-/**\n- * Adds the contents of '.git/info/alternates'. The previous contents of\n- * alternates_info will be discarded.\n- */\n-void get_alternates_file(struct strbuf *alt_info);\ndiff --git a/builtin.h b/builtin.h\nindex c6373d3289..5cf5df69f7 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -135,7 +135,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix);\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix);\n int cmd_blame(int argc, const char **argv, const char *prefix);\n int cmd_branch(int argc, const char **argv, const char *prefix);\n-int cmd_bugreport(int argc, const char **argv, const char *prefix);\n int cmd_bundle(int argc, const char **argv, const char *prefix);\n int cmd_cat_file(int argc, const char **argv, const char *prefix);\n int cmd_checkout(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/bugreport.c b/builtin/bugreport.c\ndeleted file mode 100644\nindex 0784bdc42a..0000000000\n--- a/builtin/bugreport.c\n+++ /dev/null\n@@ -1,90 +0,0 @@\n-#include \"builtin.h\"\n-#include \"bugreport.h\"\n-#include \"stdio.h\"\n-#include \"strbuf.h\"\n-#include \"time.h\"\n-\n-int get_bug_template(struct strbuf *template)\n-{\n-\tconst char template_text[] =\n-\"Thank you for filling out a Git bug report!\\n\"\n-\"Please answer the following questions to help us understand your issue.\\n\"\n-\"\\n\"\n-\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n-\"\\n\"\n-\"What did you expect to happen? (Expected behavior)\\n\"\n-\"\\n\"\n-\"What happened instead? (Actual behavior)\\n\"\n-\"\\n\"\n-\"What's different between what you expected and what actually happened?\\n\"\n-\"\\n\"\n-\"Anything else you want to add:\\n\"\n-\"\\n\"\n-\"Please review the rest of the bug report below.\\n\"\n-\"You can delete any lines you don't wish to send.\\n\";\n-\n-\tstrbuf_reset(template);\n-\tstrbuf_add(template, template_text, strlen(template_text));\n-\treturn 0;\n-}\n-\n-void add_header(FILE *report, const char *title)\n-{\n-\tstruct strbuf buffer = STRBUF_INIT;\n-\tstrbuf_addf(&buffer, \"\\n\\n[%s]\\n\", title);\n-\tstrbuf_write(&buffer, report);\n-}\n-\n-int cmd_bugreport(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf buffer = STRBUF_INIT;\n-\tstruct strbuf report_path = STRBUF_INIT;\n-\tFILE *report;\n-\ttime_t now = time(NULL);\n-\n-\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n-\tstrbuf_addftime(&report_path, \"%F\", gmtime(&now), 0, 0);\n-\tstrbuf_addstr(&report_path, \".txt\");\n-\n-\treport = fopen_for_writing(report_path.buf);\n-\n-\tget_bug_template(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\t// add other contents\n-\tadd_header(report, \"System Info\");\n-\tget_system_info(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\tadd_header(report, \"Whitelisted Config\");\n-\tget_whitelisted_config(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\tadd_header(report, \"Populated Hooks\");\n-\tget_populated_hooks(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\tadd_header(report, \"Object Counts\");\n-\tget_loose_object_summary(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\tadd_header(report, \"Packed Object Summary\");\n-\tget_packed_object_summary(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\tadd_header(report, \"Object Info Data\");\n-\tget_object_info_summary(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\tadd_header(report, \"Alternates File\");\n-\tget_alternates_file(&buffer);\n-\tstrbuf_write(&buffer, report);\n-\n-\t// Close file\n-\t// open file in editor\n-\tlaunch_editor(report_path, NULL, NULL);\n-\tfclose(report);\n-\n-\tlaunch_editor(report_path.buf, NULL, NULL);\n-\treturn 0;\n-}\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/config.c b/config.c\nindex e7052b3977..baab4a916e 100644\n--- a/config.c\n+++ b/config.c\n@@ -3312,6 +3312,23 @@ enum config_scope current_config_scope(void)\n \t\treturn current_parsing_scope;\n }\n \n+const char *config_scope_to_string(enum config_scope scope)\n+{\n+\tswitch (scope) {\n+\tcase CONFIG_SCOPE_SYSTEM:\n+\t\treturn \"system\";\n+\tcase CONFIG_SCOPE_GLOBAL:\n+\t\treturn \"global\";\n+\tcase CONFIG_SCOPE_REPO:\n+\t\treturn \"repo\";\n+\tcase CONFIG_SCOPE_CMDLINE:\n+\t\treturn \"cmdline\";\n+\tcase CONFIG_SCOPE_UNKNOWN:\n+\tdefault:\n+\t\treturn \"unknown\";\n+\t}\n+}\n+\n int lookup_config(const char **mapping, int nr_mapping, const char *var)\n {\n \tint i;\ndiff --git a/config.h b/config.h\nindex 91fd4c5e96..c8bf296dcc 100644\n--- a/config.h\n+++ b/config.h\n@@ -303,6 +303,7 @@ enum config_scope {\n };\n \n enum config_scope current_config_scope(void);\n+const char *config_scope_to_string(enum config_scope);\n const char *current_config_origin_type(void);\n const char *current_config_name(void);\n \ndiff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\nnew file mode 100755\nindex 0000000000..06b8e0c3c4\n--- /dev/null\n+++ b/generate-bugreport-config-safelist.sh\n@@ -0,0 +1,22 @@\n+#!/bin/sh\n+\n+cat <<EOF\n+/* Automatically generated by bugreport-generate-config-safelist.sh */\n+\n+\n+static const char *bugreport_config_safelist[] = {\n+EOF\n+\n+# cat all regular files in Documentation/config\n+find Documentation/config -type f -exec cat {} \\; |\n+# print the command name which matches the bugreport-include macro\n+sed -n 's/^\\(.*\\) \\+bugreport:include.* ::$/\\1/p' |\n+sort |\n+while read line\n+do\n+\techo \"\t\\\"$line\\\",\"\n+done\n+\n+cat <<EOF\n+};\n+EOF\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..eca6a00c30\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,24 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\twhile read line\n+\tdo\n+\t\techo \"\t\\\"$line\\\",\"\n+\tdone\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/git.c b/git.c\nindex 2d6a64f019..ce6ab0ece2 100644\n--- a/git.c\n+++ b/git.c\n@@ -473,7 +473,6 @@ static struct cmd_struct commands[] = {\n \t{ \"bisect--helper\", cmd_bisect__helper, RUN_SETUP },\n \t{ \"blame\", cmd_blame, RUN_SETUP },\n \t{ \"branch\", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },\n-\t{ \"bugreport\", cmd_bugreport, RUN_SETUP },\n \t{ \"bundle\", cmd_bundle, RUN_SETUP_GENTLY | NO_PARSEOPT },\n \t{ \"cat-file\", cmd_cat_file, RUN_SETUP },\n \t{ \"check-attr\", cmd_check_attr, RUN_SETUP },\ndiff --git a/help.c b/help.c\nindex cf67624a94..6d1bd17971 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\n@@ -707,8 +622,34 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void list_version_info(struct strbuf *buf, int build_options)\n+{\n+\tstrbuf_reset(buf);\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addf(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\tstrbuf_addf(buf, \"shell-path: %s\\n\", SHELL_PATH);\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -722,25 +663,9 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tlist_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 7a455beeb7..54f6b5f793 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n@@ -38,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void list_version_info(struct strbuf *buf, int build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\ndiff --git a/http-fetch.c b/http-fetch.c\nindex a32ac118d9..31844812a1 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -3,9 +3,18 @@\n #include \"exec-cmd.h\"\n #include \"http.h\"\n #include \"walker.h\"\n+#include \"version.h\"\n \n static const char http_fetch_usage[] = \"git http-fetch \"\n-\"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url\";\n+\"[-c] [-t] [-a] [-v] [-V] [--recover] [-w ref] [--stdin] commit-id url\";\n+\n+void NORETURN version_info()\n+{\n+\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n+\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n+\tprintf(\"curl version: %s\\n\", curl_version());\n+\texit(0);\n+}\n \n int cmd_main(int argc, const char **argv)\n {\n@@ -26,6 +35,8 @@ int cmd_main(int argc, const char **argv)\n \t\t} else if (argv[arg][1] == 'a') {\n \t\t} else if (argv[arg][1] == 'v') {\n \t\t\tget_verbosely = 1;\n+\t\t} else if (argv[arg][1] == 'V') {\n+\t\t\tversion_info();\n \t\t} else if (argv[arg][1] == 'w') {\n \t\t\twrite_ref = &argv[arg + 1];\n \t\t\targ++;\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..6eb2ee4f66\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,41 @@\n+#!/bin/bash\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+check_all_headers_populated() {\n+\twhile read -r line; do\n+\t\tif [$(grep $HEADER_PATTERN $line)]; then\n+\t\t\tread -r nextline\n+\t\t\tif [-z $nextline]; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\tgit bugreport &&\n+\tcheck_all_headers_populated <git-bugreport-* &&\n+\trm git-bugreport-*\n+'\n+\n+test_expect_success '--output puts the report in the provided dir' '\n+\tmkdir foo/ &&\n+\tgit bugreport -o foo/ &&\n+\ttest -f foo/git-bugreport-* &&\n+\trm -fr foo/\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\tgrep usage output &&\n+\ttest ! -f git-bugreport-*\n+'\n+\n+test_done\n\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388051","messageId":"20191213004312.169753-3-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 02/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:42:59Z","receivedAt":"2019-12-13T00:43:34Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\nbuiltin/clean.o, and builtin/config.o. This meant that help.o was\nunusable outside of the context of the main Git executable.\n\nTo make help.o usable by other commands again, move list_config_help()\ninto builtin/help.c (where it makes sense to assume other builtin libraries\nare present).\n\nWhen command-list.h is included but a member is not used, we start to\nhear a compiler warning. Since the config list is generated in a fairly\ndifferent way than the command list, and since commands and config\noptions are semantically different, move the config list into its own\nheader and move the generator into its own script and build rule.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore             |  1 +\n Makefile               | 16 ++++++--\n builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n generate-cmdlist.sh    | 19 ----------\n generate-configlist.sh | 24 ++++++++++++\n help.c                 | 85 -----------------------------------------\n help.h                 |  1 -\n 7 files changed, 123 insertions(+), 109 deletions(-)\n create mode 100755 generate-configlist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 055a84c4a8..5dde2cc4c8 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -189,6 +189,7 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 9dff91436e..c49f55a521 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -815,6 +815,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n@@ -2127,7 +2128,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2147,6 +2148,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2784,7 +2791,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-GEN_HDRS := command-list.h unicode-width.h\n+GEN_HDRS := config-list.h command-list.h unicode-width.h\n EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n@@ -2807,7 +2814,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -3110,7 +3117,8 @@ clean: profile-clean coverage-clean cocciclean\n \t$(RM) $(HCC)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n+\t$(RM) $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..eca6a00c30\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,24 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\twhile read line\n+\tdo\n+\t\techo \"\t\\\"$line\\\",\"\n+\tdone\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/help.c b/help.c\nindex cf67624a94..a21487db77 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\ndiff --git a/help.h b/help.h\nindex 7a455beeb7..9071894e8c 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388052","messageId":"20191213004312.169753-2-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 01/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:42:58Z","receivedAt":"2019-12-13T00:43:35Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach Git how to prompt the user for a good bug report: reproduction\nsteps, expected behavior, and actual behavior. Later, Git can learn how\nto collect some diagnostic information from the repository.\n\nIf users can send us a well-written bug report which contains diagnostic\ninformation we would otherwise need to ask the user for, we can reduce\nthe number of question-and-answer round trips between the reporter and\nthe Git contributor.\n\nUsers may also wish to send a report like this to their local \"Git\nexpert\" if they have put their repository into a state they are confused\nby.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                      |  1 +\n Documentation/git-bugreport.txt | 43 ++++++++++++++++++++\n Makefile                        |  5 +++\n bugreport.c                     | 69 +++++++++++++++++++++++++++++++++\n t/t0091-bugreport.sh            | 41 ++++++++++++++++++++\n 5 files changed, 159 insertions(+)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 89b3b79c1a..055a84c4a8 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -25,6 +25,7 @@\n /git-bisect--helper\n /git-blame\n /git-branch\n+/git-bugreport\n /git-bundle\n /git-cat-file\n /git-check-attr\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..75f0c80acf\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,43 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [-o | --output <path>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+The following information is captured automatically:\n+\n+ - Git version (`git version --build-options`)\n+ - Machine information (`uname -a`)\n+ - Versions of various dependencies\n+ - Git config contents (`git config --show-origin --list`)\n+ - The names of all configured git-hooks in `.git/hooks/`\n+\n+OPTIONS\n+-------\n+-o [<path>]::\n+--output [<path>]::\n+\tPlace the resulting bug report file in <path> instead of the root of the\n+\tGit repository.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex b7d7374dac..9dff91436e 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -2448,6 +2449,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\ndiff --git a/bugreport.c b/bugreport.c\nnew file mode 100644\nindex 0000000000..5495b31674\n--- /dev/null\n+++ b/bugreport.c\n@@ -0,0 +1,69 @@\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output <file>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to send.\\n\");\n+\n+\tstrbuf_addstr(template, template_text);\n+\treturn 0;\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tFILE *report;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"\", bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\tif (option_output) {\n+\t\tstrbuf_addstr(&report_path, option_output);\n+\t\tstrbuf_complete(&report_path, '/');\n+\t}\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, \"%F\", gmtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\n+\tget_bug_template(&buffer);\n+\n+\treport = fopen_for_writing(report_path.buf);\n+\tstrbuf_write(&buffer, report);\n+\tfclose(report);\n+\n+\tlaunch_editor(report_path.buf, NULL, NULL);\n+\treturn 0;\n+}\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..6eb2ee4f66\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,41 @@\n+#!/bin/bash\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+check_all_headers_populated() {\n+\twhile read -r line; do\n+\t\tif [$(grep $HEADER_PATTERN $line)]; then\n+\t\t\tread -r nextline\n+\t\t\tif [-z $nextline]; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\tgit bugreport &&\n+\tcheck_all_headers_populated <git-bugreport-* &&\n+\trm git-bugreport-*\n+'\n+\n+test_expect_success '--output puts the report in the provided dir' '\n+\tmkdir foo/ &&\n+\tgit bugreport -o foo/ &&\n+\ttest -f foo/git-bugreport-* &&\n+\trm -fr foo/\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\tgrep usage output &&\n+\ttest ! -f git-bugreport-*\n+'\n+\n+test_done\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388053","messageId":"20191213004312.169753-4-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 03/15] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:00Z","receivedAt":"2019-12-13T00:43:36Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Knowing which version of Git a user has and how it was built allows us\nto more precisely pin down the circumstances when a certain issue\noccurs, so teach bugreport how to tell us the same output as 'git\nversion --build-options'.\n\nIt's not ideal to directly call 'git version --build-options' because\nthat output goes to stdout. Instead, wrap the version string in a helper\nwithin help.[ch] library, and call that helper from within the bugreport\nlibrary.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 23 ++++++++++++++++++++++-\n help.c      | 45 +++++++++++++++++++++++++++------------------\n help.h      |  1 +\n 3 files changed, 50 insertions(+), 19 deletions(-)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 5495b31674..59d8b5a3af 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,8 +1,20 @@\n-#include \"builtin.h\"\n+#include \"cache.h\"\n #include \"parse-options.h\"\n #include \"stdio.h\"\n #include \"strbuf.h\"\n #include \"time.h\"\n+#include \"help.h\"\n+\n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\tstruct strbuf version_info = STRBUF_INIT;\n+\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, \"git version:\\n\");\n+\tlist_version_info(&version_info, 1);\n+\tstrbuf_addbuf(sys_info, &version_info);\n+\tstrbuf_complete_line(sys_info);\n+}\n \n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n@@ -32,6 +44,11 @@ static int get_bug_template(struct strbuf *template)\n \treturn 0;\n }\n \n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n int cmd_main(int argc, const char **argv)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n@@ -60,6 +77,10 @@ int cmd_main(int argc, const char **argv)\n \n \tget_bug_template(&buffer);\n \n+\t// add other contents\n+\tget_header(&buffer, \"System Info\");\n+\tget_system_info(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\ndiff --git a/help.c b/help.c\nindex a21487db77..a43693fca5 100644\n--- a/help.c\n+++ b/help.c\n@@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void list_version_info(struct strbuf *buf, int build_options)\n+{\n+\tstrbuf_reset(buf);\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addf(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -637,25 +662,9 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tlist_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 9071894e8c..54f6b5f793 100644\n--- a/help.h\n+++ b/help.h\n@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void list_version_info(struct strbuf *buf, int build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388054","messageId":"20191213004312.169753-5-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 04/15] help: add shell-path to --build-options","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:01Z","receivedAt":"2019-12-13T00:43:39Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It may be useful to know which shell Git was built to try to point to,\nin the event that shell-based Git commands are failing. $SHELL_PATH is\nset during the build and used to launch the manpage viewer, as well as\nby git-compat-util.h, and it's used during tests. 'git version\n--build-options' is encouraged for use in bug reports, so it makes sense\nto include this information there.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n help.c | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/help.c b/help.c\nindex a43693fca5..6d1bd17971 100644\n--- a/help.c\n+++ b/help.c\n@@ -642,6 +642,7 @@ void list_version_info(struct strbuf *buf, int build_options)\n \t\t\tstrbuf_addf(buf, \"no commit associated with this build\\n\");\n \t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n \t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\tstrbuf_addf(buf, \"shell-path: %s\\n\", SHELL_PATH);\n \t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n \t}\n }\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388055","messageId":"20191213004312.169753-6-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 05/15] bugreport: add uname info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:02Z","receivedAt":"2019-12-13T00:43:42Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The contents of uname() can give us some insight into what sort of\nsystem the user is running on, and help us replicate their setup if need\nbe. The domainname field is not guaranteed to be available, so don't\ncollect it.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 59d8b5a3af..9c69e3fa34 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -8,12 +8,25 @@\n static void get_system_info(struct strbuf *sys_info)\n {\n \tstruct strbuf version_info = STRBUF_INIT;\n+\tstruct utsname uname_info;\n \n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, \"git version:\\n\");\n \tlist_version_info(&version_info, 1);\n \tstrbuf_addbuf(sys_info, &version_info);\n \tstrbuf_complete_line(sys_info);\n+\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname -a: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, \"uname() failed with code %d\\n\", errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.nodename,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388056","messageId":"20191213004312.169753-7-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 06/15] bugreport: add glibc version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:03Z","receivedAt":"2019-12-13T00:43:44Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"To help pinpoint the source of a regression, it is useful to know the\nversion of libc which the user's Git client was built with. Let's\ninclude it alongside the other versioning information, which is used to\nidentify how the client was built.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 9c69e3fa34..af715dc157 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"time.h\"\n #include \"help.h\"\n+#include <gnu/libc-version.h>\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -27,6 +28,10 @@ static void get_system_info(struct strbuf *sys_info)\n \t\t\t    uname_info.release,\n \t\t\t    uname_info.version,\n \t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, \"glibc version: \");\n+\tstrbuf_addstr(sys_info, gnu_get_libc_version());\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388057","messageId":"20191213004312.169753-9-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 08/15] bugreport: include user interactive shell","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:05Z","receivedAt":"2019-12-13T00:43:49Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It's possible a user may complain about the way that Git interacts with\ntheir interactive shell, e.g. autocompletion or shell prompt. In that\ncase, it's useful for us to know which shell they're using\ninteractively.\n\n$SHELL isn't set by every shell, but getenv() returns NULL in the\nevent the variable isn't found, so we'll see a line like \"$SHELL:\n(null)\" to tell us that variable wasn't set.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex f5598513d9..759cc0b0f8 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -45,6 +45,9 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_addstr(sys_info, gnu_get_libc_version());\n \tstrbuf_complete_line(sys_info);\n \n+\tstrbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n+\t\t    getenv(\"SHELL\"));\n+\n \tstrbuf_addstr(sys_info, \"git-http-fetch -V:\\n\");\n \tget_http_version_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388058","messageId":"20191213004312.169753-8-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 07/15] bugreport: add curl version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:04Z","receivedAt":"2019-12-13T00:43:50Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It's possible for git-http* to be built separately from git; in that\ncase we want to know what version of cURL is used by git-http*, not\nnecessarily which version was present at git-bugreport's build time.\nSo instead, ask git-http-fetch for the version information it knows\nabout.\n\ngit-http-fetch was chosen as git-http-backend was described as a\nserver-side implementation, and as an accidental fetch in case of\nproblems was considered less harmful than an accidental push.\n\nSince it could have been built at a different time, also report the\nversion and built-from commit of git-http-fetch alongside the cURL info.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-http-fetch.txt |  5 +++++\n bugreport.c                      | 16 ++++++++++++++++\n http-fetch.c                     | 13 ++++++++++++-\n 3 files changed, 33 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt\nindex 666b042679..2894c5e82b 100644\n--- a/Documentation/git-http-fetch.txt\n+++ b/Documentation/git-http-fetch.txt\n@@ -10,6 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [--stdin] <commit> <url>\n+'git http-fetch' [-V]\n \n DESCRIPTION\n -----------\n@@ -30,6 +31,10 @@ commit-id::\n -v::\n \tReport what is downloaded.\n \n+-V::\n+\tReport information about the version of git-http-fetch, including the\n+\tversions of its dependencies.\n+\n -w <filename>::\n         Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on\n         the local end after the transfer is complete.\ndiff --git a/bugreport.c b/bugreport.c\nindex af715dc157..f5598513d9 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -5,6 +5,18 @@\n #include \"time.h\"\n #include \"help.h\"\n #include <gnu/libc-version.h>\n+#include \"run-command.h\"\n+\n+static void get_http_version_info(struct strbuf *http_info)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\targv_array_push(&cp.args, \"git\");\n+\targv_array_push(&cp.args, \"http-fetch\");\n+\targv_array_push(&cp.args, \"-V\");\n+\tif (capture_command(&cp, http_info, 0))\n+\t    strbuf_addstr(http_info, \"'git-http-fetch -V' not supported\\n\");\n+}\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -32,6 +44,10 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_addstr(sys_info, \"glibc version: \");\n \tstrbuf_addstr(sys_info, gnu_get_libc_version());\n \tstrbuf_complete_line(sys_info);\n+\n+\tstrbuf_addstr(sys_info, \"git-http-fetch -V:\\n\");\n+\tget_http_version_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/http-fetch.c b/http-fetch.c\nindex a32ac118d9..31844812a1 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -3,9 +3,18 @@\n #include \"exec-cmd.h\"\n #include \"http.h\"\n #include \"walker.h\"\n+#include \"version.h\"\n \n static const char http_fetch_usage[] = \"git http-fetch \"\n-\"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url\";\n+\"[-c] [-t] [-a] [-v] [-V] [--recover] [-w ref] [--stdin] commit-id url\";\n+\n+void NORETURN version_info()\n+{\n+\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n+\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n+\tprintf(\"curl version: %s\\n\", curl_version());\n+\texit(0);\n+}\n \n int cmd_main(int argc, const char **argv)\n {\n@@ -26,6 +35,8 @@ int cmd_main(int argc, const char **argv)\n \t\t} else if (argv[arg][1] == 'a') {\n \t\t} else if (argv[arg][1] == 'v') {\n \t\t\tget_verbosely = 1;\n+\t\t} else if (argv[arg][1] == 'V') {\n+\t\t\tversion_info();\n \t\t} else if (argv[arg][1] == 'w') {\n \t\t\twrite_ref = &argv[arg + 1];\n \t\t\targ++;\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388059","messageId":"20191213004312.169753-10-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:06Z","receivedAt":"2019-12-13T00:43:51Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Add a new step to the build to generate a safelist of git-config\nvariables which are appropriate to include in the output of\ngit-bugreport. New variables can be added to the safelist by annotating\ntheir documentation in Documentation/config with the\n\"bugreport\" macro, which is recognized by AsciiDoc and\nAsciiDoctor.\n\nSome configs are private in nature, and can contain remote URLs,\npasswords, or other sensitive information. In the event that a user\ndoesn't notice their information while reviewing a bugreport, that user\nmay leak their credentials to other individuals, mailing lists, or bug\ntracking tools inadvertently. Heuristic blocklisting of configuration\nkeys is imperfect and prone to false negatives; given the nature of the\ninformation which can be leaked, a safelist is more reliable.\n\nIn order to prevent staleness of the safelist, add a mechanism to\ngenerate the safelist from annotations in the config documentation,\nwhere contributors are already used to documenting their new config\nkeys.\n\nImplement a new no-op \"bugreport\" macro for use as\n\"bugreport:include[x]\" to annotate the config keys that should be\nincluded in the automatically generated safelist. Use \"exclude\" for the\nothers.\n\nWith Asciidoctor, it's ok to say \"bugreport:include[]\", but AsciiDoc\nseems to want something between the brackets. A bit unfortunate, but\nnot a huge problem -- we'll just provide an \"x\".\n\n\"doc-diff\" reports that this macro doesn't render at all. That is,\nthese are both empty after this commit:\n\n  cd Documentation\n  ./doc-diff --asciidoctor :/\"bugreport: add tool\" HEAD\n  ./doc-diff --asciidoc    :/\"bugreport: add tool\" HEAD\n\nDiffing the rendered HTML shows that there is some small amount of\nwhitespace and comments added. That shouldn't be a problem.\n\nWe could perhaps let the implementation verify that the \"action\" is one\nof \"include\" and \"exclude\". For the Asciidoctor implementation that\nshould be straightforward, but for AsciiDoc I don't immediately know how\nto do it. Anyway, if someone stumbles on the keyboard and writes\n\"bugreport:icndule\", they'll \"only\" miss out on the config key being\nincluded in the safelist. If this were a blocklist, the consequences of\na misspelled target could be a lot more severe.\n\nAdditionally, add annotations to the sendemail config documentation in\norder to demonstrate a proof of concept.\n\nHelped-by: Martin Ågren <martin.agren@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                              |  1 +\n Documentation/asciidoc.conf             |  8 +++\n Documentation/asciidoctor-extensions.rb |  7 +++\n Documentation/config/sendemail.txt      | 68 ++++++++++++-------------\n Makefile                                | 14 +++--\n generate-bugreport-config-safelist.sh   | 22 ++++++++\n 6 files changed, 83 insertions(+), 37 deletions(-)\n create mode 100755 generate-bugreport-config-safelist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 5dde2cc4c8..30935621d9 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -191,6 +191,7 @@\n /gitweb/static/gitweb.min.*\n /config-list.h\n /command-list.h\n+/bugreport-config-safelist.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\nindex 8fc4b67081..5d5359fcf9 100644\n--- a/Documentation/asciidoc.conf\n+++ b/Documentation/asciidoc.conf\n@@ -6,9 +6,13 @@\n #\n # Show Git link as: <command>(<section>); if section is defined, else just show\n # the command.\n+#\n+# The bugreport macro does nothing as far as rendering is\n+# concerned -- we just grep for it in the sources.\n \n [macros]\n (?su)[\\\\]?(?P<name>linkgit):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n+(?su)[\\\\]?(?P<name>bugreport):(?P<action>\\S*?)\\[(?P<attrlist>.*?)\\]=\n \n [attributes]\n asterisk=&#42;\n@@ -28,6 +32,8 @@ ifdef::backend-docbook[]\n {0#<citerefentry>}\n {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n {0#</citerefentry>}\n+[bugreport-inlinemacro]\n+{0#}\n endif::backend-docbook[]\n \n ifdef::backend-docbook[]\n@@ -94,4 +100,6 @@ ifdef::backend-xhtml11[]\n git-relative-html-prefix=\n [linkgit-inlinemacro]\n <a href=\"{git-relative-html-prefix}{target}.html\">{target}{0?({0})}</a>\n+[bugreport-inlinemacro]\n+<!-- -->\n endif::backend-xhtml11[]\ndiff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\nindex d906a00803..750bdff9af 100644\n--- a/Documentation/asciidoctor-extensions.rb\n+++ b/Documentation/asciidoctor-extensions.rb\n@@ -37,6 +37,10 @@ module Git\n           output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n         end\n         output\n+\n+    class BugReportProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n+      def process(parent, action, attrs)\n+        \"\"\n       end\n     end\n   end\n@@ -45,4 +49,7 @@ end\n Asciidoctor::Extensions.register do\n   inline_macro Git::Documentation::LinkGitProcessor, :linkgit\n   postprocessor Git::Documentation::DocumentPostProcessor\n+  # The bugreport macro does nothing as far as rendering is\n+  # concerned -- we just grep for it in the sources.\n+  inline_macro Git::Documentation::BugReportProcessor, :bugreport\n end\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 0006faf800..92f5082013 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -1,63 +1,63 @@\n-sendemail.identity::\n+sendemail.identity bugreport:exclude[x] ::\n \tA configuration identity. When given, causes values in the\n \t'sendemail.<identity>' subsection to take precedence over\n \tvalues in the 'sendemail' section. The default identity is\n \tthe value of `sendemail.identity`.\n \n-sendemail.smtpEncryption::\n+sendemail.smtpEncryption bugreport:include[x] ::\n \tSee linkgit:git-send-email[1] for description.  Note that this\n \tsetting is not subject to the 'identity' mechanism.\n \n-sendemail.smtpssl (deprecated)::\n+sendemail.smtpssl (deprecated) bugreport:exclude[x] ::\n \tDeprecated alias for 'sendemail.smtpEncryption = ssl'.\n \n-sendemail.smtpsslcertpath::\n+sendemail.smtpsslcertpath bugreport:exclude[x] ::\n \tPath to ca-certificates (either a directory or a single file).\n \tSet it to an empty string to disable certificate verification.\n \n-sendemail.<identity>.*::\n+sendemail.<identity>.* bugreport:exclude[x] ::\n \tIdentity-specific versions of the 'sendemail.*' parameters\n \tfound below, taking precedence over those when this\n \tidentity is selected, through either the command-line or\n \t`sendemail.identity`.\n \n-sendemail.aliasesFile::\n-sendemail.aliasFileType::\n-sendemail.annotate::\n-sendemail.bcc::\n-sendemail.cc::\n-sendemail.ccCmd::\n-sendemail.chainReplyTo::\n-sendemail.confirm::\n-sendemail.envelopeSender::\n-sendemail.from::\n-sendemail.multiEdit::\n-sendemail.signedoffbycc::\n-sendemail.smtpPass::\n-sendemail.suppresscc::\n-sendemail.suppressFrom::\n-sendemail.to::\n-sendemail.tocmd::\n-sendemail.smtpDomain::\n-sendemail.smtpServer::\n-sendemail.smtpServerPort::\n-sendemail.smtpServerOption::\n-sendemail.smtpUser::\n-sendemail.thread::\n-sendemail.transferEncoding::\n-sendemail.validate::\n-sendemail.xmailer::\n+sendemail.aliasesFile bugreport:exclude[x] ::\n+sendemail.aliasFileType bugreport:exclude[x] ::\n+sendemail.annotate bugreport:include[x] ::\n+sendemail.bcc bugreport:include[x] ::\n+sendemail.cc bugreport:include[x] ::\n+sendemail.ccCmd bugreport:include[x] ::\n+sendemail.chainReplyTo bugreport:include[x] ::\n+sendemail.confirm bugreport:include[x] ::\n+sendemail.envelopeSender bugreport:include[x] ::\n+sendemail.from bugreport:include[x] ::\n+sendemail.multiEdit bugreport:include[x] ::\n+sendemail.signedoffbycc bugreport:include[x] ::\n+sendemail.smtpPass bugreport:exclude[x] ::\n+sendemail.suppresscc bugreport:include[x] ::\n+sendemail.suppressFrom bugreport:include[x] ::\n+sendemail.to bugreport:include[x] ::\n+sendemail.tocmd bugreport:include[x] ::\n+sendemail.smtpDomain bugreport:include[x] ::\n+sendemail.smtpServer bugreport:include[x] ::\n+sendemail.smtpServerPort bugreport:include[x] ::\n+sendemail.smtpServerOption bugreport:include[x] ::\n+sendemail.smtpUser bugreport:exclude[x] ::\n+sendemail.thread bugreport:include[x] ::\n+sendemail.transferEncoding bugreport:include[x] ::\n+sendemail.validate bugreport:include[x] ::\n+sendemail.xmailer bugreport:include[x] ::\n \tSee linkgit:git-send-email[1] for description.\n \n-sendemail.signedoffcc (deprecated)::\n+sendemail.signedoffcc (deprecated) bugreport:exclude[x] ::\n \tDeprecated alias for `sendemail.signedoffbycc`.\n \n-sendemail.smtpBatchSize::\n+sendemail.smtpBatchSize bugreport:include[x] ::\n \tNumber of messages to be sent per connection, after that a relogin\n \twill happen.  If the value is 0 or undefined, send all messages in\n \tone connection.\n \tSee also the `--batch-size` option of linkgit:git-send-email[1].\n \n-sendemail.smtpReloginDelay::\n+sendemail.smtpReloginDelay bugreport:include[x] ::\n \tSeconds wait before reconnecting to smtp server.\n \tSee also the `--relogin-delay` option of linkgit:git-send-email[1].\ndiff --git a/Makefile b/Makefile\nindex c49f55a521..76dc51e2b1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -651,7 +651,7 @@ install-perl-script: $(SCRIPT_PERL_GEN)\n install-python-script: $(SCRIPT_PYTHON_GEN)\n \t$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n \n-.PHONY: clean-perl-script clean-sh-script clean-python-script\n+.PHONY: clean-perl-script clean-sh-script clean-python-script clean-script-dependencies\n clean-sh-script:\n \t$(RM) $(SCRIPT_SH_GEN)\n clean-perl-script:\n@@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n \n GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n+GENERATED_H += bugreport-config-safelist.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n \t$(FIND) . \\\n@@ -2161,6 +2162,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\tcommand-list.txt >$@+ && mv $@+ $@\n \n+bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n+\n+bugreport-config-safelist.h: Documentation/config/*.txt\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n@@ -2791,7 +2798,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-GEN_HDRS := config-list.h command-list.h unicode-width.h\n+GEN_HDRS := config-list.h command-list.h unicode-width.h bugreport-config-safelist.h\n EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n@@ -3117,7 +3124,8 @@ clean: profile-clean coverage-clean cocciclean\n \t$(RM) $(HCC)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo\n+\t$(RM) config-list.h command-list.h bugreport-config-safelist.h\n \t$(RM) $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\ndiff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\nnew file mode 100755\nindex 0000000000..06b8e0c3c4\n--- /dev/null\n+++ b/generate-bugreport-config-safelist.sh\n@@ -0,0 +1,22 @@\n+#!/bin/sh\n+\n+cat <<EOF\n+/* Automatically generated by bugreport-generate-config-safelist.sh */\n+\n+\n+static const char *bugreport_config_safelist[] = {\n+EOF\n+\n+# cat all regular files in Documentation/config\n+find Documentation/config -type f -exec cat {} \\; |\n+# print the command name which matches the bugreport-include macro\n+sed -n 's/^\\(.*\\) \\+bugreport:include.* ::$/\\1/p' |\n+sort |\n+while read line\n+do\n+\techo \"\t\\\"$line\\\",\"\n+done\n+\n+cat <<EOF\n+};\n+EOF\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388060","messageId":"20191213004312.169753-11-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:07Z","receivedAt":"2019-12-13T00:43:54Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach bugreport to gather the values of config options which are present\nin 'bugreport-config-safelist.h'.\n\nMany config options are sensitive, and many Git add-ons use config\noptions which git-core does not know about; it is better only to gather\nconfig options which we know to be safe, rather than excluding options\nwhich we know to be unsafe.\n\nTaking the build-time generated array and putting it into a set saves us\ntime - since git_config_bugreport() is called for every option the user\nhas configured, performing option lookup in constant time is a useful\noptimization.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 71 insertions(+), 1 deletion(-)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 759cc0b0f8..1fca28f0b9 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -6,6 +6,9 @@\n #include \"help.h\"\n #include <gnu/libc-version.h>\n #include \"run-command.h\"\n+#include \"config.h\"\n+#include \"bugreport-config-safelist.h\"\n+#include \"khash.h\"\n \n static void get_http_version_info(struct strbuf *http_info)\n {\n@@ -18,6 +21,41 @@ static void get_http_version_info(struct strbuf *http_info)\n \t    strbuf_addstr(http_info, \"'git-http-fetch -V' not supported\\n\");\n }\n \n+KHASH_INIT(cfg_set, const char*, int, 0, kh_str_hash_func, kh_str_hash_equal);\n+\n+struct cfgset {\n+\tkh_cfg_set_t set;\n+};\n+\n+struct cfgset safelist;\n+\n+static void cfgset_init(struct cfgset *set, size_t initial_size)\n+{\n+\tmemset(&set->set, 0, sizeof(set->set));\n+\tif (initial_size)\n+\t\tkh_resize_cfg_set(&set->set, initial_size);\n+}\n+\n+static int cfgset_insert(struct cfgset *set, const char *cfg_key)\n+{\n+\tint added;\n+\tkh_put_cfg_set(&set->set, cfg_key, &added);\n+\tprintf(\"ESS: added %s\\n\", cfg_key);\n+\treturn !added;\n+}\n+\n+static int cfgset_contains(struct cfgset *set, const char *cfg_key)\n+{\n+\tkhiter_t pos = kh_get_cfg_set(&set->set, cfg_key);\n+\treturn pos != kh_end(&set->set);\n+}\n+\n+static void cfgset_clear(struct cfgset *set)\n+{\n+\tkh_release_cfg_set(&set->set);\n+\tcfgset_init(set, 0);\n+}\n+\n static void get_system_info(struct strbuf *sys_info)\n {\n \tstruct strbuf version_info = STRBUF_INIT;\n@@ -53,6 +91,36 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_complete_line(sys_info);\n }\n \n+static void gather_safelist()\n+{\n+\tint index;\n+\tint safelist_len = sizeof(bugreport_config_safelist) / sizeof(const char *);\n+\tcfgset_init(&safelist, safelist_len);\n+\tfor (index = 0; index < safelist_len; index++)\n+\t\tcfgset_insert(&safelist, bugreport_config_safelist[index]);\n+\n+}\n+\n+static int git_config_bugreport(const char *var, const char *value, void *cb)\n+{\n+\tstruct strbuf *config_info = (struct strbuf *)cb;\n+\n+\tif (cfgset_contains(&safelist, var))\n+\t\tstrbuf_addf(config_info,\n+\t\t\t    \"%s (%s) : %s\\n\",\n+\t\t\t    var, config_scope_to_string(current_config_scope()),\n+\t\t\t    value);\n+\n+\treturn 0;\n+}\n+\n+static void get_safelisted_config(struct strbuf *config_info)\n+{\n+\tgather_safelist();\n+\tgit_config(git_config_bugreport, config_info);\n+\tcfgset_clear(&safelist);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -114,10 +182,12 @@ int cmd_main(int argc, const char **argv)\n \n \tget_bug_template(&buffer);\n \n-\t// add other contents\n \tget_header(&buffer, \"System Info\");\n \tget_system_info(&buffer);\n \n+\tget_header(&buffer, \"Safelisted Config Info\");\n+\tget_safelisted_config(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388061","messageId":"20191213004312.169753-12-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 11/15] bugreport: collect list of populated hooks","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:08Z","receivedAt":"2019-12-13T00:43:56Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Occasionally a failure a user is seeing may be related to a specific\nhook which is being run, perhaps without the user realizing. While the\ncontents of hooks can be sensitive - containing user data or process\ninformation specific to the user's organization - simply knowing that a\nhook is being run at a certain stage can help us to understand whether\nsomething is going wrong.\n\nWithout a definitive list of hook names within the code, we compile our\nown list from the documentation. This is likely prone to bitrot. To\nreduce the amount of code humans need to read, we turn the list into a\nstring_list and iterate over it (as we are calling the same find_hook\noperation on each string). However, since bugreport should primarily be\ncalled by the user, the performance loss from massaging the string\nseems acceptable.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 55 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 1fca28f0b9..f89cb8d754 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -9,6 +9,7 @@\n #include \"config.h\"\n #include \"bugreport-config-safelist.h\"\n #include \"khash.h\"\n+#include \"run-command.h\"\n \n static void get_http_version_info(struct strbuf *http_info)\n {\n@@ -121,6 +122,57 @@ static void get_safelisted_config(struct strbuf *config_info)\n \tcfgset_clear(&safelist);\n }\n \n+static void get_populated_hooks(struct strbuf *hook_info)\n+{\n+\t/*\n+\t * Doesn't look like there is a list of all possible hooks; so below is\n+\t * a transcription of `git help hook`.\n+\t */\n+\tconst char *hooks = \"applypatch-msg,\"\n+\t\t\t    \"pre-applypatch,\"\n+\t\t\t    \"post-applypatch,\"\n+\t\t\t    \"pre-commit,\"\n+\t\t\t    \"pre-merge-commit,\"\n+\t\t\t    \"prepare-commit-msg,\"\n+\t\t\t    \"commit-msg,\"\n+\t\t\t    \"post-commit,\"\n+\t\t\t    \"pre-rebase,\"\n+\t\t\t    \"post-checkout,\"\n+\t\t\t    \"post-merge,\"\n+\t\t\t    \"pre-push,\"\n+\t\t\t    \"pre-receive,\"\n+\t\t\t    \"update,\"\n+\t\t\t    \"post-receive,\"\n+\t\t\t    \"post-update,\"\n+\t\t\t    \"push-to-checkout,\"\n+\t\t\t    \"pre-auto-gc,\"\n+\t\t\t    \"post-rewrite,\"\n+\t\t\t    \"sendemail-validate,\"\n+\t\t\t    \"fsmonitor-watchman,\"\n+\t\t\t    \"p4-pre-submit,\"\n+\t\t\t    \"post-index-changex\";\n+\tstruct string_list hooks_list = STRING_LIST_INIT_DUP;\n+\tstruct string_list_item *iter = NULL;\n+\tint nongit_ok;\n+\n+\tsetup_git_directory_gently(&nongit_ok);\n+\n+\tif (nongit_ok) {\n+\t\tstrbuf_addstr(hook_info,\n+\t\t\t\"not run from a git repository - no hooks to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstring_list_split(&hooks_list, hooks, ',', -1);\n+\n+\tfor_each_string_list_item(iter, &hooks_list) {\n+\t\tif (find_hook(iter->string)) {\n+\t\t\tstrbuf_addstr(hook_info, iter->string);\n+\t\t\tstrbuf_complete_line(hook_info);\n+\t\t}\n+\t}\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -188,6 +240,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Safelisted Config Info\");\n \tget_safelisted_config(&buffer);\n \n+\tget_header(&buffer, \"Configured Hooks\");\n+\tget_populated_hooks(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388062","messageId":"20191213004312.169753-13-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 12/15] bugreport: count loose objects","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:09Z","receivedAt":"2019-12-13T00:43:59Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The number of unpacked objects in a user's repository may help us\nunderstand the root of the problem they're seeing, especially if a\ncommand is running unusually slowly.\n\nRather than directly invoking 'git-count-objects', which may sometimes\nfail unexpectedly on Git for Windows, manually count the contents of\n.git/objects. Additionally, since we may wish to inspect other\ndirectories' contents for bugreport in the future, put the directory\nlisting into a helper function.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 64 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex f89cb8d754..3abb83d77f 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -173,6 +173,67 @@ static void get_populated_hooks(struct strbuf *hook_info)\n \t}\n }\n \n+static int is_hex(const char *string, size_t count)\n+{\n+\tfor (; count; string++, count--) {\n+\t\tif (!isxdigit(*string))\n+\t\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\n+\n+static void get_loose_object_summary(struct strbuf *obj_info) {\n+\tstruct dirent *d = NULL;\n+\tDIR *dir, *subdir = NULL;\n+\tsize_t dir_len;\n+\tstruct strbuf dirpath = STRBUF_INIT;\n+\n+\tstrbuf_addstr(&dirpath, get_object_directory());\n+\tstrbuf_complete(&dirpath, '/');\n+\n+\tdir = opendir(dirpath.buf);\n+\tif (!dir) {\n+\t\tstrbuf_addf(obj_info, \"could not open object directory '%s'\\n\",\n+\t\t\t    dirpath.buf);\n+\t\tstrbuf_release(&dirpath);\n+\t\treturn;\n+\t}\n+\n+\tdir_len = dirpath.len;\n+\n+\twhile ((d = readdir(dir))) {\n+\t\tint object_count = 0;\n+\t\tchar subdir_name[3];\n+\n+\t\tif (d->d_type != DT_DIR)\n+\t\t\tcontinue;\n+\n+\t\tif ((strlen(d->d_name) != 2) || (!is_hex(d->d_name, 2)))\n+\t\t\tcontinue;\n+\n+\t\t/* copy directory name + \\0 */\n+\t\tmemcpy(subdir_name, d->d_name, 3);\n+\n+\t\tstrbuf_setlen(&dirpath, dir_len);\n+\t\tstrbuf_addstr(&dirpath, d->d_name);\n+\n+\t\tsubdir = opendir(dirpath.buf);\n+\t\tif (!subdir)\n+\t\t\tcontinue;\n+\t\twhile ((d = readdir(subdir)))\n+\t\t\tif (d->d_type == DT_REG)\n+\t\t\t\tobject_count++;\n+\n+\t\tclosedir(subdir);\n+\n+\t\tstrbuf_addf(obj_info, \"%s: %d\\n\", subdir_name, object_count);\n+\t}\n+\n+\n+\tclosedir(dir);\n+\tstrbuf_release(&dirpath);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -243,6 +304,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Configured Hooks\");\n \tget_populated_hooks(&buffer);\n \n+\tget_header(&buffer, \"Loose Object Counts\");\n+\tget_loose_object_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388063","messageId":"20191213004312.169753-14-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 13/15] bugreport: add packed object summary","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:10Z","receivedAt":"2019-12-13T00:44:02Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Alongside the list of loose objects, it's useful to see the list of\nobject packs as well. It can help us to examine what Git did and did not\npack.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 31 +++++++++++++++++++++++++++++++\n 1 file changed, 31 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 3abb83d77f..992d8f9de7 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -234,6 +234,34 @@ static void get_loose_object_summary(struct strbuf *obj_info) {\n \tstrbuf_release(&dirpath);\n }\n \n+static void get_packed_object_summary(struct strbuf *obj_info)\n+{\n+\tstruct strbuf dirpath = STRBUF_INIT;\n+\tstruct dirent *d;\n+\tDIR *dir = NULL;\n+\n+\tstrbuf_addstr(&dirpath, get_object_directory());\n+\tstrbuf_complete(&dirpath, '/');\n+\tstrbuf_addstr(&dirpath, \"pack/\");\n+\n+\tdir = opendir(dirpath.buf);\n+\tif (!dir) {\n+\t\tstrbuf_addf(obj_info, \"could not open packed object directory '%s'\\n\",\n+\t\t\t    dirpath.buf);\n+\t\tstrbuf_release(&dirpath);\n+\t\treturn;\n+\t}\n+\n+\twhile ((d = readdir(dir))) {\n+\t\tstrbuf_addbuf(obj_info, &dirpath);\n+\t\tstrbuf_addstr(obj_info, d->d_name);\n+\t\tstrbuf_complete_line(obj_info);\n+\t}\n+\n+\tclosedir(dir);\n+\tstrbuf_release(&dirpath);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -307,6 +335,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Loose Object Counts\");\n \tget_loose_object_summary(&buffer);\n \n+\tget_header(&buffer, \"Packed Object Summary\");\n+\tget_packed_object_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388064","messageId":"20191213004312.169753-15-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 14/15] bugreport: list contents of $OBJDIR/info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:11Z","receivedAt":"2019-12-13T00:44:03Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Miscellaneous information used about the object store can end up in\n.git/objects/info; this can help us understand what may be going on with\nthe object store when the user is reporting a bug. Otherwise, it could\nbe difficult to track down what is going wrong with an object which\nisn't kept locally to .git/objects/ or .git/objects/pack. Having some\nunderstanding of where the user's objects may be kept can save us some\nhops during the bug reporting process.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 48 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 992d8f9de7..5d300f1c5f 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -262,6 +262,51 @@ static void get_packed_object_summary(struct strbuf *obj_info)\n \tstrbuf_release(&dirpath);\n }\n \n+static void list_contents_of_dir_recursively(struct strbuf *contents,\n+\t\t\t\t      \t     struct strbuf *dirpath)\n+{\n+\tstruct dirent *d;\n+\tDIR *dir;\n+\tsize_t path_len;\n+\n+\tdir = opendir(dirpath->buf);\n+\tif (!dir)\n+\t\treturn;\n+\n+\tstrbuf_complete(dirpath, '/');\n+\tpath_len = dirpath->len;\n+\n+\twhile ((d = readdir(dir))) {\n+\t\tif (!strcmp(d->d_name, \".\") || !strcmp(d->d_name, \"..\"))\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_addbuf(contents, dirpath);\n+\t\tstrbuf_addstr(contents, d->d_name);\n+\t\tstrbuf_complete_line(contents);\n+\n+\t\tif (d->d_type == DT_DIR) {\n+\t\t\tstrbuf_addstr(dirpath, d->d_name);\n+\t\t\tlist_contents_of_dir_recursively(contents, dirpath);\n+\t\t}\n+\t\tstrbuf_setlen(dirpath, path_len);\n+\t}\n+\n+\tclosedir(dir);\n+}\n+\n+static void get_object_info_summary(struct strbuf *obj_info)\n+{\n+\tstruct strbuf dirpath = STRBUF_INIT;\n+\n+\tstrbuf_addstr(&dirpath, get_object_directory());\n+\tstrbuf_complete(&dirpath, '/');\n+\tstrbuf_addstr(&dirpath, \"info/\");\n+\n+\tlist_contents_of_dir_recursively(obj_info, &dirpath);\n+\n+\tstrbuf_release(&dirpath);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -338,6 +383,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Packed Object Summary\");\n \tget_packed_object_summary(&buffer);\n \n+\tget_header(&buffer, \"Object Info Summary\");\n+\tget_object_info_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388065","messageId":"20191213004312.169753-16-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v4 15/15] bugreport: summarize contents of alternates file","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-13T00:43:12Z","receivedAt":"2019-12-13T00:44:06Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"In some cases, it could be that the user is having a problem with an\nobject which isn't present in their normal object directory. We can get\na hint that that might be the case by examining the list of alternates\nwhere their object may be stored instead. Since paths to alternates may\nbe sensitive, we'll instead count how many alternates have been\nspecified and note how many of them exist or are broken.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 39 +++++++++++++++++++++++++++++++++++++++\n 1 file changed, 39 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 5d300f1c5f..d2a3fb1f67 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -307,6 +307,42 @@ static void get_object_info_summary(struct strbuf *obj_info)\n \tstrbuf_release(&dirpath);\n }\n \n+static void get_alternates_summary(struct strbuf *alternates_info)\n+{\n+\tstruct strbuf alternates_path = STRBUF_INIT;\n+\tstruct strbuf alternate = STRBUF_INIT;\n+\tFILE *file;\n+\tsize_t exists = 0, broken = 0;\n+\n+\tstrbuf_addstr(&alternates_path, get_object_directory());\n+\tstrbuf_complete(&alternates_path, '/');\n+\tstrbuf_addstr(&alternates_path, \"info/alternates\");\n+\n+\tfile = fopen(alternates_path.buf, \"r\");\n+\tif (!file) {\n+\t\tstrbuf_addstr(alternates_info, \"No alternates file found.\\n\");\n+\t\tstrbuf_release(&alternates_path);\n+\t\treturn;\n+\t}\n+\n+\twhile (strbuf_getline(&alternate, file) != EOF) {\n+\t\tif (!access(alternate.buf, F_OK))\n+\t\t\texists++;\n+\t\telse\n+\t\t\tbroken++;\n+\t}\n+\n+\tstrbuf_addf(alternates_info,\n+\t\t    \"%zd alternates found (%zd working, %zd broken)\\n\",\n+\t\t    exists + broken,\n+\t\t    exists,\n+\t\t    broken);\n+\n+\tfclose(file);\n+\tstrbuf_release(&alternate);\n+\tstrbuf_release(&alternates_path);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -386,6 +422,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Object Info Summary\");\n \tget_object_info_summary(&buffer);\n \n+\tget_header(&buffer, \"Alternates\");\n+\tget_alternates_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.24.1.735.g03f4e72817-goog\n\n"},{"id":"388162","messageId":"xmqqv9qkhrtd.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-3-emilyshaffer@google.com","subject":"Re: [PATCH v4 02/15] help: move list_config_help to builtin/help","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T20:51:58Z","receivedAt":"2019-12-13T20:52:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\n> builtin/clean.o, and builtin/config.o. This meant that help.o was\n> unusable outside of the context of the main Git executable.\n>\n> To make help.o usable by other commands again, move list_config_help()\n> into builtin/help.c (where it makes sense to assume other builtin libraries\n> are present).\n>\n> When command-list.h is included but a member is not used, we start to\n> hear a compiler warning. Since the config list is generated in a fairly\n> different way than the command list, and since commands and config\n> options are semantically different, move the config list into its own\n> header and move the generator into its own script and build rule.\n>\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n\nOK.  Looks like a clean-up that is very worthy even without the\nremainder of the topic.\n\nThanks.\n\n>  .gitignore             |  1 +\n>  Makefile               | 16 ++++++--\n>  builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n>  generate-cmdlist.sh    | 19 ----------\n>  generate-configlist.sh | 24 ++++++++++++\n>  help.c                 | 85 -----------------------------------------\n>  help.h                 |  1 -\n>  7 files changed, 123 insertions(+), 109 deletions(-)\n>  create mode 100755 generate-configlist.sh\n>\n> diff --git a/.gitignore b/.gitignore\n> index 055a84c4a8..5dde2cc4c8 100644\n> --- a/.gitignore\n> +++ b/.gitignore\n> @@ -189,6 +189,7 @@\n>  /gitweb/gitweb.cgi\n>  /gitweb/static/gitweb.js\n>  /gitweb/static/gitweb.min.*\n> +/config-list.h\n>  /command-list.h\n>  *.tar.gz\n>  *.dsc\n> diff --git a/Makefile b/Makefile\n> index 9dff91436e..c49f55a521 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -815,6 +815,7 @@ LIB_FILE = libgit.a\n>  XDIFF_LIB = xdiff/lib.a\n>  VCSSVN_LIB = vcs-svn/lib.a\n>  \n> +GENERATED_H += config-list.h\n>  GENERATED_H += command-list.h\n>  \n>  LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n> @@ -2127,7 +2128,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n>  \n>  help.sp help.s help.o: command-list.h\n>  \n> -builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n> +builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n>  builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n>  \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n>  \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n> @@ -2147,6 +2148,12 @@ $(BUILT_INS): git$X\n>  \tln -s $< $@ 2>/dev/null || \\\n>  \tcp $< $@\n>  \n> +config-list.h: generate-configlist.sh\n> +\n> +config-list.h:\n> +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n> +\t\t>$@+ && mv $@+ $@\n> +\n>  command-list.h: generate-cmdlist.sh command-list.txt\n>  \n>  command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n> @@ -2784,7 +2791,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n>  .PHONY: sparse $(SP_OBJ)\n>  sparse: $(SP_OBJ)\n>  \n> -GEN_HDRS := command-list.h unicode-width.h\n> +GEN_HDRS := config-list.h command-list.h unicode-width.h\n>  EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n>  ifndef GCRYPT_SHA256\n>  \tEXCEPT_HDRS += sha256/gcrypt.h\n> @@ -2807,7 +2814,7 @@ hdr-check: $(HCO)\n>  style:\n>  \tgit clang-format --style file --diff --extensions c,h\n>  \n> -check: command-list.h\n> +check: config-list.h command-list.h\n>  \t@if sparse; \\\n>  \tthen \\\n>  \t\techo >&2 \"Use 'make sparse' instead\"; \\\n> @@ -3110,7 +3117,8 @@ clean: profile-clean coverage-clean cocciclean\n>  \t$(RM) $(HCC)\n>  \t$(RM) -r bin-wrappers $(dep_dirs)\n>  \t$(RM) -r po/build/\n> -\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n> +\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n> +\t$(RM) $(ETAGS_TARGET) tags cscope*\n>  \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n>  \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n>  \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\n> diff --git a/builtin/help.c b/builtin/help.c\n> index e5590d7787..1c5f2b9255 100644\n> --- a/builtin/help.c\n> +++ b/builtin/help.c\n> @@ -8,6 +8,7 @@\n>  #include \"parse-options.h\"\n>  #include \"run-command.h\"\n>  #include \"column.h\"\n> +#include \"config-list.h\"\n>  #include \"help.h\"\n>  #include \"alias.h\"\n>  \n> @@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n>  \tNULL\n>  };\n>  \n> +struct slot_expansion {\n> +\tconst char *prefix;\n> +\tconst char *placeholder;\n> +\tvoid (*fn)(struct string_list *list, const char *prefix);\n> +\tint found;\n> +};\n> +\n> +static void list_config_help(int for_human)\n> +{\n> +\tstruct slot_expansion slot_expansions[] = {\n> +\t\t{ \"advice\", \"*\", list_config_advices },\n> +\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n> +\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n> +\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n> +\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n> +\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n> +\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n> +\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n> +\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> +\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> +\t\t{ NULL, NULL, NULL }\n> +\t};\n> +\tconst char **p;\n> +\tstruct slot_expansion *e;\n> +\tstruct string_list keys = STRING_LIST_INIT_DUP;\n> +\tint i;\n> +\n> +\tfor (p = config_name_list; *p; p++) {\n> +\t\tconst char *var = *p;\n> +\t\tstruct strbuf sb = STRBUF_INIT;\n> +\n> +\t\tfor (e = slot_expansions; e->prefix; e++) {\n> +\n> +\t\t\tstrbuf_reset(&sb);\n> +\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n> +\t\t\tif (!strcasecmp(var, sb.buf)) {\n> +\t\t\t\te->fn(&keys, e->prefix);\n> +\t\t\t\te->found++;\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t}\n> +\t\tstrbuf_release(&sb);\n> +\t\tif (!e->prefix)\n> +\t\t\tstring_list_append(&keys, var);\n> +\t}\n> +\n> +\tfor (e = slot_expansions; e->prefix; e++)\n> +\t\tif (!e->found)\n> +\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n> +\t\t\t    e->prefix, e->placeholder);\n> +\n> +\tstring_list_sort(&keys);\n> +\tfor (i = 0; i < keys.nr; i++) {\n> +\t\tconst char *var = keys.items[i].string;\n> +\t\tconst char *wildcard, *tag, *cut;\n> +\n> +\t\tif (for_human) {\n> +\t\t\tputs(var);\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\twildcard = strchr(var, '*');\n> +\t\ttag = strchr(var, '<');\n> +\n> +\t\tif (!wildcard && !tag) {\n> +\t\t\tputs(var);\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tif (wildcard && !tag)\n> +\t\t\tcut = wildcard;\n> +\t\telse if (!wildcard && tag)\n> +\t\t\tcut = tag;\n> +\t\telse\n> +\t\t\tcut = wildcard < tag ? wildcard : tag;\n> +\n> +\t\t/*\n> +\t\t * We may produce duplicates, but that's up to\n> +\t\t * git-completion.bash to handle\n> +\t\t */\n> +\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n> +\t}\n> +\tstring_list_clear(&keys, 0);\n> +}\n> +\n>  static enum help_format parse_help_format(const char *format)\n>  {\n>  \tif (!strcmp(format, \"man\"))\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> index 71158f7d8b..45fecf8bdf 100755\n> --- a/generate-cmdlist.sh\n> +++ b/generate-cmdlist.sh\n> @@ -76,23 +76,6 @@ print_command_list () {\n>  \techo \"};\"\n>  }\n>  \n> -print_config_list () {\n> -\tcat <<EOF\n> -static const char *config_name_list[] = {\n> -EOF\n> -\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> -\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> -\tsort |\n> -\twhile read line\n> -\tdo\n> -\t\techo \"\t\\\"$line\\\",\"\n> -\tdone\n> -\tcat <<EOF\n> -\tNULL,\n> -};\n> -EOF\n> -}\n> -\n>  exclude_programs=\n>  while test \"--exclude-program\" = \"$1\"\n>  do\n> @@ -113,5 +96,3 @@ echo\n>  define_category_names \"$1\"\n>  echo\n>  print_command_list \"$1\"\n> -echo\n> -print_config_list\n> diff --git a/generate-configlist.sh b/generate-configlist.sh\n> new file mode 100755\n> index 0000000000..eca6a00c30\n> --- /dev/null\n> +++ b/generate-configlist.sh\n> @@ -0,0 +1,24 @@\n> +#!/bin/sh\n> +\n> +echo \"/* Automatically generated by generate-configlist.sh */\"\n> +echo\n> +\n> +print_config_list () {\n> +\tcat <<EOF\n> +static const char *config_name_list[] = {\n> +EOF\n> +\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> +\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> +\tsort |\n> +\twhile read line\n> +\tdo\n> +\t\techo \"\t\\\"$line\\\",\"\n> +\tdone\n> +\tcat <<EOF\n> +\tNULL,\n> +};\n> +EOF\n> +}\n> +\n> +echo\n> +print_config_list\n> diff --git a/help.c b/help.c\n> index cf67624a94..a21487db77 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -407,91 +407,6 @@ void list_common_guides_help(void)\n>  \tputchar('\\n');\n>  }\n>  \n> -struct slot_expansion {\n> -\tconst char *prefix;\n> -\tconst char *placeholder;\n> -\tvoid (*fn)(struct string_list *list, const char *prefix);\n> -\tint found;\n> -};\n> -\n> -void list_config_help(int for_human)\n> -{\n> -\tstruct slot_expansion slot_expansions[] = {\n> -\t\t{ \"advice\", \"*\", list_config_advices },\n> -\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n> -\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n> -\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n> -\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n> -\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n> -\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n> -\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n> -\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> -\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> -\t\t{ NULL, NULL, NULL }\n> -\t};\n> -\tconst char **p;\n> -\tstruct slot_expansion *e;\n> -\tstruct string_list keys = STRING_LIST_INIT_DUP;\n> -\tint i;\n> -\n> -\tfor (p = config_name_list; *p; p++) {\n> -\t\tconst char *var = *p;\n> -\t\tstruct strbuf sb = STRBUF_INIT;\n> -\n> -\t\tfor (e = slot_expansions; e->prefix; e++) {\n> -\n> -\t\t\tstrbuf_reset(&sb);\n> -\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n> -\t\t\tif (!strcasecmp(var, sb.buf)) {\n> -\t\t\t\te->fn(&keys, e->prefix);\n> -\t\t\t\te->found++;\n> -\t\t\t\tbreak;\n> -\t\t\t}\n> -\t\t}\n> -\t\tstrbuf_release(&sb);\n> -\t\tif (!e->prefix)\n> -\t\t\tstring_list_append(&keys, var);\n> -\t}\n> -\n> -\tfor (e = slot_expansions; e->prefix; e++)\n> -\t\tif (!e->found)\n> -\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n> -\t\t\t    e->prefix, e->placeholder);\n> -\n> -\tstring_list_sort(&keys);\n> -\tfor (i = 0; i < keys.nr; i++) {\n> -\t\tconst char *var = keys.items[i].string;\n> -\t\tconst char *wildcard, *tag, *cut;\n> -\n> -\t\tif (for_human) {\n> -\t\t\tputs(var);\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\twildcard = strchr(var, '*');\n> -\t\ttag = strchr(var, '<');\n> -\n> -\t\tif (!wildcard && !tag) {\n> -\t\t\tputs(var);\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\tif (wildcard && !tag)\n> -\t\t\tcut = wildcard;\n> -\t\telse if (!wildcard && tag)\n> -\t\t\tcut = tag;\n> -\t\telse\n> -\t\t\tcut = wildcard < tag ? wildcard : tag;\n> -\n> -\t\t/*\n> -\t\t * We may produce duplicates, but that's up to\n> -\t\t * git-completion.bash to handle\n> -\t\t */\n> -\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n> -\t}\n> -\tstring_list_clear(&keys, 0);\n> -}\n> -\n>  static int get_alias(const char *var, const char *value, void *data)\n>  {\n>  \tstruct string_list *list = data;\n> diff --git a/help.h b/help.h\n> index 7a455beeb7..9071894e8c 100644\n> --- a/help.h\n> +++ b/help.h\n> @@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n>  void list_common_cmds_help(void);\n>  void list_all_cmds_help(void);\n>  void list_common_guides_help(void);\n> -void list_config_help(int for_human);\n>  \n>  void list_all_main_cmds(struct string_list *list);\n>  void list_all_other_cmds(struct string_list *list);\n"},{"id":"388166","messageId":"xmqqr218hr56.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-4-emilyshaffer@google.com","subject":"Re: [PATCH v4 03/15] bugreport: gather git version and build info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:06:29Z","receivedAt":"2019-12-13T21:06:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> Knowing which version of Git a user has and how it was built allows us\n> to more precisely pin down the circumstances when a certain issue\n> occurs, so teach bugreport how to tell us the same output as 'git\n> version --build-options'.\n>\n> It's not ideal to directly call 'git version --build-options' because\n> that output goes to stdout. Instead, wrap the version string in a helper\n> within help.[ch] library, and call that helper from within the bugreport\n> library.\n\nMove to strbuf() from stdio makes sense.  \n\n> +\t// add other contents\n\nStyle.\n\n> diff --git a/help.h b/help.h\n> index 9071894e8c..54f6b5f793 100644\n> --- a/help.h\n> +++ b/help.h\n> @@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n>  void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n>  int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n\n\nMany new helpers are called get_frotz(), but only one among these is\ncalled list_version_info().  I do not think the naming of the\nget_*() ones, that are private to the bugreport tool, matters that\nmuch, but unlike \"list_commands()\" whose purpose is to list the\ncommands ;-), the new function does not list versions---it just\ngives information about a single version which is the one that is\nbeing run, so perhaps it is a misnomer.\n\n>  void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n> +void list_version_info(struct strbuf *buf, int build_options);\n\nIt is not clear to the readers build_options is a boolean that\ntells the function to include (or not to include) build options.\nPerhaps rename it to \"int show_build_options\" or something?\n\n"},{"id":"388167","messageId":"xmqqmubwhqvy.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-6-emilyshaffer@google.com","subject":"Re: [PATCH v4 05/15] bugreport: add uname info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:12:01Z","receivedAt":"2019-12-13T21:12:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> The contents of uname() can give us some insight into what sort of\n> system the user is running on, and help us replicate their setup if need\n> be. The domainname field is not guaranteed to be available, so don't\n> collect it.\n\nIt was surprising to me that we do use \"struct utsname\" somewhere in\nthe system ;-) ... so at least we know this is just as portable as\nthe remainder of Git, which is good.\n\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  bugreport.c | 13 +++++++++++++\n>  1 file changed, 13 insertions(+)\n>\n> diff --git a/bugreport.c b/bugreport.c\n> index 59d8b5a3af..9c69e3fa34 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -8,12 +8,25 @@\n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n>  \tstruct strbuf version_info = STRBUF_INIT;\n> +\tstruct utsname uname_info;\n>  \n>  \t/* get git version from native cmd */\n>  \tstrbuf_addstr(sys_info, \"git version:\\n\");\n>  \tlist_version_info(&version_info, 1);\n>  \tstrbuf_addbuf(sys_info, &version_info);\n>  \tstrbuf_complete_line(sys_info);\n> +\n> +\t/* system call for other version info */\n> +\tstrbuf_addstr(sys_info, \"uname -a: \");\n> +\tif (uname(&uname_info))\n> +\t\tstrbuf_addf(sys_info, \"uname() failed with code %d\\n\", errno);\n> +\telse\n> +\t\tstrbuf_addf(sys_info, \"%s %s %s %s %s\\n\",\n> +\t\t\t    uname_info.sysname,\n> +\t\t\t    uname_info.nodename,\n> +\t\t\t    uname_info.release,\n> +\t\t\t    uname_info.version,\n> +\t\t\t    uname_info.machine);\n>  }\n>  \n>  static const char * const bugreport_usage[] = {\n"},{"id":"388168","messageId":"xmqqimmjj557.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-7-emilyshaffer@google.com","subject":"Re: [PATCH v4 06/15] bugreport: add glibc version","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:18:44Z","receivedAt":"2019-12-13T21:18:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> To help pinpoint the source of a regression, it is useful to know the\n> version of libc which the user's Git client was built with. Let's\n> include it alongside the other versioning information, which is used to\n> identify how the client was built.\n>\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  bugreport.c | 5 +++++\n>  1 file changed, 5 insertions(+)\n\nThis is the first iffy one in the series.  It is unreasonable to\nassume that we can dictate that Git can be built only on glibc\nsystems, no?\n\nMaking this conditional, perhaps make \"bugreport.c\" depend on\n\"extern void get_compiler_info(struct strbuf *sys_info)\" and require\nthe function to be defined in compat/; the glibc variant that uses\ngnu_get_libc_version() would become just one of them.\n\n> diff --git a/bugreport.c b/bugreport.c\n> index 9c69e3fa34..af715dc157 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -4,6 +4,7 @@\n>  #include \"strbuf.h\"\n>  #include \"time.h\"\n>  #include \"help.h\"\n> +#include <gnu/libc-version.h>\n>  \n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n> @@ -27,6 +28,10 @@ static void get_system_info(struct strbuf *sys_info)\n>  \t\t\t    uname_info.release,\n>  \t\t\t    uname_info.version,\n>  \t\t\t    uname_info.machine);\n> +\n> +\tstrbuf_addstr(sys_info, \"glibc version: \");\n> +\tstrbuf_addstr(sys_info, gnu_get_libc_version());\n> +\tstrbuf_complete_line(sys_info);\n>  }\n>  \n>  static const char * const bugreport_usage[] = {\n"},{"id":"388169","messageId":"xmqqd0crj4qk.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-8-emilyshaffer@google.com","subject":"Re: [PATCH v4 07/15] bugreport: add curl version","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:27:31Z","receivedAt":"2019-12-13T21:27:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> It's possible for git-http* to be built separately from git; in that\n> case we want to know what version of cURL is used by git-http*, not\n> necessarily which version was present at git-bugreport's build time.\n> So instead, ask git-http-fetch for the version information it knows\n> about.\n>\n> git-http-fetch was chosen as git-http-backend was described as a\n> server-side implementation, and as an accidental fetch in case of\n> problems was considered less harmful than an accidental push.\n>\n> Since it could have been built at a different time, also report the\n> version and built-from commit of git-http-fetch alongside the cURL info.\n\nOne possible issue I have is that I was hoping that eventually we\ncan discard \"git http-fetch\" altogether sometime in the future.\nDoes anybody still use the dumb HTTP transport seriously?  \n\nAnd the first move in that direction would be to allow the system be\nbuilt without http-fetch, even if git-remote-curl (and its aliases)\nwould still be built to access smart-http transports.\n\nSo, I am not sure.  This is just the matter of adding an out-of-line\nhidden option used only for environment inspection, so if it can be\ndone to git-remote-curl, that would probably be much more future\nproof.\n\n> diff --git a/bugreport.c b/bugreport.c\n> index af715dc157..f5598513d9 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -5,6 +5,18 @@\n>  #include \"time.h\"\n>  #include \"help.h\"\n>  #include <gnu/libc-version.h>\n> +#include \"run-command.h\"\n> +\n> +static void get_http_version_info(struct strbuf *http_info)\n> +{\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\n> +\targv_array_push(&cp.args, \"git\");\n> +\targv_array_push(&cp.args, \"http-fetch\");\n> +\targv_array_push(&cp.args, \"-V\");\n> +\tif (capture_command(&cp, http_info, 0))\n> +\t    strbuf_addstr(http_info, \"'git-http-fetch -V' not supported\\n\");\n\nOK.  We probably can also take the compile-time \"NO_CURL\" into account,\nso that we can tell a misconfigured installation that wanted to have\nCURL but failed to install a usable http-fetch and an installation\nthat deliberately omitted anything cURL?\n\n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n> @@ -32,6 +44,10 @@ static void get_system_info(struct strbuf *sys_info)\n>  \tstrbuf_addstr(sys_info, \"glibc version: \");\n>  \tstrbuf_addstr(sys_info, gnu_get_libc_version());\n>  \tstrbuf_complete_line(sys_info);\n> +\n> +\tstrbuf_addstr(sys_info, \"git-http-fetch -V:\\n\");\n> +\tget_http_version_info(sys_info);\n> +\tstrbuf_complete_line(sys_info);\n>  }\n>  \n>  static const char * const bugreport_usage[] = {\n> diff --git a/http-fetch.c b/http-fetch.c\n> index a32ac118d9..31844812a1 100644\n> --- a/http-fetch.c\n> +++ b/http-fetch.c\n> @@ -3,9 +3,18 @@\n>  #include \"exec-cmd.h\"\n>  #include \"http.h\"\n>  #include \"walker.h\"\n> +#include \"version.h\"\n>  \n>  static const char http_fetch_usage[] = \"git http-fetch \"\n> -\"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url\";\n> +\"[-c] [-t] [-a] [-v] [-V] [--recover] [-w ref] [--stdin] commit-id url\";\n> +\n> +void NORETURN version_info()\n\nvoid NORETURN version_info(void)\n\n\n> +{\n> +\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n> +\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n> +\tprintf(\"curl version: %s\\n\", curl_version());\n> +\texit(0);\n> +}\n>  \n>  int cmd_main(int argc, const char **argv)\n>  {\n> @@ -26,6 +35,8 @@ int cmd_main(int argc, const char **argv)\n>  \t\t} else if (argv[arg][1] == 'a') {\n>  \t\t} else if (argv[arg][1] == 'v') {\n>  \t\t\tget_verbosely = 1;\n> +\t\t} else if (argv[arg][1] == 'V') {\n> +\t\t\tversion_info();\n>  \t\t} else if (argv[arg][1] == 'w') {\n>  \t\t\twrite_ref = &argv[arg + 1];\n>  \t\t\targ++;\n"},{"id":"388171","messageId":"xmqq8snfj47x.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-9-emilyshaffer@google.com","subject":"Re: [PATCH v4 08/15] bugreport: include user interactive shell","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:38:42Z","receivedAt":"2019-12-13T21:38:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> It's possible a user may complain about the way that Git interacts with\n> their interactive shell, e.g. autocompletion or shell prompt. In that\n> case, it's useful for us to know which shell they're using\n> interactively.\n>\n> $SHELL isn't set by every shell, but getenv() returns NULL in the\n> event the variable isn't found, so we'll see a line like \"$SHELL:\n> (null)\" to tell us that variable wasn't set.\n\nDo not depend on vsnprintf() from glibc that accepts NULL and shows\n\"(null)\".  You can segfault on systems without glibc that way.\n\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  bugreport.c | 3 +++\n>  1 file changed, 3 insertions(+)\n>\n> diff --git a/bugreport.c b/bugreport.c\n> index f5598513d9..759cc0b0f8 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -45,6 +45,9 @@ static void get_system_info(struct strbuf *sys_info)\n>  \tstrbuf_addstr(sys_info, gnu_get_libc_version());\n>  \tstrbuf_complete_line(sys_info);\n>  \n> +\tstrbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n> +\t\t    getenv(\"SHELL\"));\n> +\n>  \tstrbuf_addstr(sys_info, \"git-http-fetch -V:\\n\");\n>  \tget_http_version_info(sys_info);\n>  \tstrbuf_complete_line(sys_info);\n"},{"id":"388172","messageId":"xmqq4ky3j3w4.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-11-emilyshaffer@google.com","subject":"Re: [PATCH v4 10/15] bugreport: add config values from safelist","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:45:47Z","receivedAt":"2019-12-13T21:45:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> Teach bugreport to gather the values of config options which are present\n> in 'bugreport-config-safelist.h'.\n>\n> Many config options are sensitive, and many Git add-ons use config\n> options which git-core does not know about; it is better only to gather\n> config options which we know to be safe, rather than excluding options\n> which we know to be unsafe.\n>\n> Taking the build-time generated array and putting it into a set saves us\n> time - since git_config_bugreport() is called for every option the user\n> has configured, performing option lookup in constant time is a useful\n> optimization.\n\nInteresting.  I actually was expecting the look-up to go the other\nway around.  We know the safe keys, so iterate over them and grab\ntheir values, if defined.  No need for hashes or anything, but just\na simple linear list of safe stuff.\n\nBut that is too simple-minded.  If we wanted to safelist foo.*.bar,\nwhere '*' can be anything, walking on the list of safe variables\nwould not work.  We must have a hash table that knows \"foo.*.bar\" is\nallowed, and while walking all the configuration keys, when we see\nfoo.a.bar, we consult \"foo.*.bar\" as well as \"foo.a.bar\" to see if\nit is whitelisted, or something like that.\n\nBut then I am not sure if this implementation does something like\nthis for three-level names.  If not, I do not see much point in use\nof the hash there either.\n\nPuzzled.\n\n>\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  bugreport.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>  1 file changed, 71 insertions(+), 1 deletion(-)\n>\n> diff --git a/bugreport.c b/bugreport.c\n> index 759cc0b0f8..1fca28f0b9 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -6,6 +6,9 @@\n>  #include \"help.h\"\n>  #include <gnu/libc-version.h>\n>  #include \"run-command.h\"\n> +#include \"config.h\"\n> +#include \"bugreport-config-safelist.h\"\n> +#include \"khash.h\"\n>  \n>  static void get_http_version_info(struct strbuf *http_info)\n>  {\n> @@ -18,6 +21,41 @@ static void get_http_version_info(struct strbuf *http_info)\n>  \t    strbuf_addstr(http_info, \"'git-http-fetch -V' not supported\\n\");\n>  }\n>  \n> +KHASH_INIT(cfg_set, const char*, int, 0, kh_str_hash_func, kh_str_hash_equal);\n> +\n> +struct cfgset {\n> +\tkh_cfg_set_t set;\n> +};\n> +\n> +struct cfgset safelist;\n> +\n> +static void cfgset_init(struct cfgset *set, size_t initial_size)\n> +{\n> +\tmemset(&set->set, 0, sizeof(set->set));\n> +\tif (initial_size)\n> +\t\tkh_resize_cfg_set(&set->set, initial_size);\n> +}\n> +\n> +static int cfgset_insert(struct cfgset *set, const char *cfg_key)\n> +{\n> +\tint added;\n> +\tkh_put_cfg_set(&set->set, cfg_key, &added);\n> +\tprintf(\"ESS: added %s\\n\", cfg_key);\n> +\treturn !added;\n> +}\n> +\n> +static int cfgset_contains(struct cfgset *set, const char *cfg_key)\n> +{\n> +\tkhiter_t pos = kh_get_cfg_set(&set->set, cfg_key);\n> +\treturn pos != kh_end(&set->set);\n> +}\n> +\n> +static void cfgset_clear(struct cfgset *set)\n> +{\n> +\tkh_release_cfg_set(&set->set);\n> +\tcfgset_init(set, 0);\n> +}\n> +\n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n>  \tstruct strbuf version_info = STRBUF_INIT;\n> @@ -53,6 +91,36 @@ static void get_system_info(struct strbuf *sys_info)\n>  \tstrbuf_complete_line(sys_info);\n>  }\n>  \n> +static void gather_safelist()\n> +{\n> +\tint index;\n> +\tint safelist_len = sizeof(bugreport_config_safelist) / sizeof(const char *);\n> +\tcfgset_init(&safelist, safelist_len);\n> +\tfor (index = 0; index < safelist_len; index++)\n> +\t\tcfgset_insert(&safelist, bugreport_config_safelist[index]);\n> +\n> +}\n> +\n> +static int git_config_bugreport(const char *var, const char *value, void *cb)\n> +{\n> +\tstruct strbuf *config_info = (struct strbuf *)cb;\n> +\n> +\tif (cfgset_contains(&safelist, var))\n> +\t\tstrbuf_addf(config_info,\n> +\t\t\t    \"%s (%s) : %s\\n\",\n> +\t\t\t    var, config_scope_to_string(current_config_scope()),\n> +\t\t\t    value);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static void get_safelisted_config(struct strbuf *config_info)\n> +{\n> +\tgather_safelist();\n> +\tgit_config(git_config_bugreport, config_info);\n> +\tcfgset_clear(&safelist);\n> +}\n> +\n>  static const char * const bugreport_usage[] = {\n>  \tN_(\"git bugreport [-o|--output <file>]\"),\n>  \tNULL\n> @@ -114,10 +182,12 @@ int cmd_main(int argc, const char **argv)\n>  \n>  \tget_bug_template(&buffer);\n>  \n> -\t// add other contents\n>  \tget_header(&buffer, \"System Info\");\n>  \tget_system_info(&buffer);\n>  \n> +\tget_header(&buffer, \"Safelisted Config Info\");\n> +\tget_safelisted_config(&buffer);\n> +\n>  \treport = fopen_for_writing(report_path.buf);\n>  \tstrbuf_write(&buffer, report);\n>  \tfclose(report);\n"},{"id":"388173","messageId":"xmqqzhfvhp8w.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-12-emilyshaffer@google.com","subject":"Re: [PATCH v4 11/15] bugreport: collect list of populated hooks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:47:27Z","receivedAt":"2019-12-13T21:47:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> +\t/*\n> +\t * Doesn't look like there is a list of all possible hooks; so below is\n> +\t * a transcription of `git help hook`.\n> +\t */\n\nWe probably would want to employ technique similar to what you used\nfor the list of safe configuration we saw in an earlier patch in the\nseries.  What's not even documented is not worth reporting ;-)\n\n> +\tconst char *hooks = \"applypatch-msg,\"\n> +\t\t\t    \"pre-applypatch,\"\n> +\t\t\t    \"post-applypatch,\"\n> +\t\t\t    \"pre-commit,\"\n> +\t\t\t    \"pre-merge-commit,\"\n> +\t\t\t    \"prepare-commit-msg,\"\n> +\t\t\t    \"commit-msg,\"\n> +\t\t\t    \"post-commit,\"\n> +\t\t\t    \"pre-rebase,\"\n> +\t\t\t    \"post-checkout,\"\n> +\t\t\t    \"post-merge,\"\n> +\t\t\t    \"pre-push,\"\n> +\t\t\t    \"pre-receive,\"\n> +\t\t\t    \"update,\"\n> +\t\t\t    \"post-receive,\"\n> +\t\t\t    \"post-update,\"\n> +\t\t\t    \"push-to-checkout,\"\n> +\t\t\t    \"pre-auto-gc,\"\n> +\t\t\t    \"post-rewrite,\"\n> +\t\t\t    \"sendemail-validate,\"\n> +\t\t\t    \"fsmonitor-watchman,\"\n> +\t\t\t    \"p4-pre-submit,\"\n> +\t\t\t    \"post-index-changex\";\n> +\tstruct string_list hooks_list = STRING_LIST_INIT_DUP;\n> +\tstruct string_list_item *iter = NULL;\n> +\tint nongit_ok;\n> +\n> +\tsetup_git_directory_gently(&nongit_ok);\n> +\n> +\tif (nongit_ok) {\n> +\t\tstrbuf_addstr(hook_info,\n> +\t\t\t\"not run from a git repository - no hooks to show\\n\");\n> +\t\treturn;\n> +\t}\n> +\n> +\tstring_list_split(&hooks_list, hooks, ',', -1);\n> +\n> +\tfor_each_string_list_item(iter, &hooks_list) {\n> +\t\tif (find_hook(iter->string)) {\n> +\t\t\tstrbuf_addstr(hook_info, iter->string);\n> +\t\t\tstrbuf_complete_line(hook_info);\n> +\t\t}\n> +\t}\n> +}\n> +\n>  static const char * const bugreport_usage[] = {\n>  \tN_(\"git bugreport [-o|--output <file>]\"),\n>  \tNULL\n> @@ -188,6 +240,9 @@ int cmd_main(int argc, const char **argv)\n>  \tget_header(&buffer, \"Safelisted Config Info\");\n>  \tget_safelisted_config(&buffer);\n>  \n> +\tget_header(&buffer, \"Configured Hooks\");\n> +\tget_populated_hooks(&buffer);\n> +\n>  \treport = fopen_for_writing(report_path.buf);\n>  \tstrbuf_write(&buffer, report);\n>  \tfclose(report);\n"},{"id":"388174","messageId":"xmqqv9qjhp28.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-13-emilyshaffer@google.com","subject":"Re: [PATCH v4 12/15] bugreport: count loose objects","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:51:27Z","receivedAt":"2019-12-13T21:51:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> The number of unpacked objects in a user's repository may help us\n> understand the root of the problem they're seeing, especially if a\n> command is running unusually slowly.\n>\n> Rather than directly invoking 'git-count-objects', which may sometimes\n> fail unexpectedly on Git for Windows, manually count the contents of\n> .git/objects.\n\nIs for_each_loose_object() or for_each_loose_file_in_objdir() not\nsufficient?  We really do *not* want a redundant implementation of\nsomething we already use elsewhere in the system, especially for the\npurpose of this program, because you would end up reporting what you\ncomputed in a way that may be quite different from what the rest of\nthe system that is actually used by the end users computes.\n\n"},{"id":"388175","messageId":"xmqqr217houg.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-14-emilyshaffer@google.com","subject":"Re: [PATCH v4 13/15] bugreport: add packed object summary","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T21:56:07Z","receivedAt":"2019-12-13T21:56:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> Alongside the list of loose objects, it's useful to see the list of\n> object packs as well. It can help us to examine what Git did and did not\n> pack.\n\nNot exactly the same comment, but is in the same spirit, as the\nprevious step applies to this one.\n\nWould it be too much work to libify the bulk of cmd_count_objects()\nthat computes numbers, making the cmd_count_objects() into a thin\nwrapper that calls the libified \"counter/collector\" function and\nprints the resulting numbers received from it?\n\nThat way, the get_packed_object_summary() can be another consumer       \nof the same \"counter/collector\" function, no?\n\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  bugreport.c | 31 +++++++++++++++++++++++++++++++\n>  1 file changed, 31 insertions(+)\n>\n> diff --git a/bugreport.c b/bugreport.c\n> index 3abb83d77f..992d8f9de7 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -234,6 +234,34 @@ static void get_loose_object_summary(struct strbuf *obj_info) {\n>  \tstrbuf_release(&dirpath);\n>  }\n>  \n> +static void get_packed_object_summary(struct strbuf *obj_info)\n> +{\n> +\tstruct strbuf dirpath = STRBUF_INIT;\n> +\tstruct dirent *d;\n> +\tDIR *dir = NULL;\n> +\n> +\tstrbuf_addstr(&dirpath, get_object_directory());\n> +\tstrbuf_complete(&dirpath, '/');\n> +\tstrbuf_addstr(&dirpath, \"pack/\");\n> +\n> +\tdir = opendir(dirpath.buf);\n> +\tif (!dir) {\n> +\t\tstrbuf_addf(obj_info, \"could not open packed object directory '%s'\\n\",\n> +\t\t\t    dirpath.buf);\n> +\t\tstrbuf_release(&dirpath);\n> +\t\treturn;\n> +\t}\n> +\n> +\twhile ((d = readdir(dir))) {\n> +\t\tstrbuf_addbuf(obj_info, &dirpath);\n> +\t\tstrbuf_addstr(obj_info, d->d_name);\n> +\t\tstrbuf_complete_line(obj_info);\n> +\t}\n> +\n> +\tclosedir(dir);\n> +\tstrbuf_release(&dirpath);\n> +}\n> +\n>  static const char * const bugreport_usage[] = {\n>  \tN_(\"git bugreport [-o|--output <file>]\"),\n>  \tNULL\n> @@ -307,6 +335,9 @@ int cmd_main(int argc, const char **argv)\n>  \tget_header(&buffer, \"Loose Object Counts\");\n>  \tget_loose_object_summary(&buffer);\n>  \n> +\tget_header(&buffer, \"Packed Object Summary\");\n> +\tget_packed_object_summary(&buffer);\n> +\n>  \treport = fopen_for_writing(report_path.buf);\n>  \tstrbuf_write(&buffer, report);\n>  \tfclose(report);\n"},{"id":"388183","messageId":"xmqq7e2zhm0i.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191213004312.169753-10-emilyshaffer@google.com","subject":"Re: [PATCH v4 09/15] bugreport: generate config safelist based on docs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-13T22:57:17Z","receivedAt":"2019-12-13T22:57:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> diff --git a/Makefile b/Makefile\n> index c49f55a521..76dc51e2b1 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -651,7 +651,7 @@ install-perl-script: $(SCRIPT_PERL_GEN)\n>  install-python-script: $(SCRIPT_PYTHON_GEN)\n>  \t$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n>  \n> -.PHONY: clean-perl-script clean-sh-script clean-python-script\n> +.PHONY: clean-perl-script clean-sh-script clean-python-script clean-script-dependencies\n>  clean-sh-script:\n>  \t$(RM) $(SCRIPT_SH_GEN)\n>  clean-perl-script:\n> @@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n>  \n>  GENERATED_H += config-list.h\n>  GENERATED_H += command-list.h\n> +GENERATED_H += bugreport-config-safelist.h\n\nOK.\n\n>  LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n>  \t$(FIND) . \\\n> @@ -2161,6 +2162,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n>  \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n>  \t\tcommand-list.txt >$@+ && mv $@+ $@\n>  \n> +bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n> +\n> +bugreport-config-safelist.h: Documentation/config/*.txt\n> +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n> +\t\t>$@+ && mv $@+ $@\n\nOK.\n\n>  SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n>  \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n>  \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n\nBut bugreport.o needs this *.h file generated before a compiler\nattempts to produce it out of bugreport.c; that dependency is\nmissing from this update to the Makefile.\n\n> @@ -2791,7 +2798,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n>  .PHONY: sparse $(SP_OBJ)\n>  sparse: $(SP_OBJ)\n>  \n> -GEN_HDRS := config-list.h command-list.h unicode-width.h\n> +GEN_HDRS := config-list.h command-list.h unicode-width.h bugreport-config-safelist.h\n>  EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n>  ifndef GCRYPT_SHA256\n>  \tEXCEPT_HDRS += sha256/gcrypt.h\n> @@ -3117,7 +3124,8 @@ clean: profile-clean coverage-clean cocciclean\n>  \t$(RM) $(HCC)\n>  \t$(RM) -r bin-wrappers $(dep_dirs)\n>  \t$(RM) -r po/build/\n> -\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n> +\t$(RM) *.pyc *.pyo */*.pyc */*.pyo\n> +\t$(RM) config-list.h command-list.h bugreport-config-safelist.h\n\nIt is kind of sad that GEN_HDRS defines the list of build artifact\nthat we should be able to clean, and then we manually list them to\nbe removed here independently.  Can we fix it up too?\n\nWe probably clean up the build/update procedure around unicode-width.h\nbefore we can do so, probably.  It may be generatable using contrib/\nscript, but as far as our normal build is concerned, it is a tracked\nsource and not part of the build byproducts, so we probably would\nwant to remove it from GEN_HDRS.  When that happens, we can $(RM)\nall of the $(GEN_HDRS) in the \"clean\" target.\n\n"},{"id":"388236","messageId":"nycvar.QRO.7.76.6.1912152116030.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20191213004312.169753-10-emilyshaffer@google.com","subject":"Re: [PATCH v4 09/15] bugreport: generate config safelist based on docs","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-12-15T20:17:57Z","receivedAt":"2019-12-15T20:18:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 12 Dec 2019, Emily Shaffer wrote:\n\n> diff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\n> new file mode 100755\n> index 0000000000..06b8e0c3c4\n> --- /dev/null\n> +++ b/generate-bugreport-config-safelist.sh\n> @@ -0,0 +1,22 @@\n> +#!/bin/sh\n> +\n> +cat <<EOF\n> +/* Automatically generated by bugreport-generate-config-safelist.sh */\n> +\n> +\n> +static const char *bugreport_config_safelist[] = {\n> +EOF\n> +\n> +# cat all regular files in Documentation/config\n> +find Documentation/config -type f -exec cat {} \\; |\n> +# print the command name which matches the bugreport-include macro\n> +sed -n 's/^\\(.*\\) \\+bugreport:include.* ::$/\\1/p' |\n\nIf you use `/  \"\\1\",/` as replacement, you can totally avoid that ugly\n`while` loop (that is unfortunately quite slow in MSYS2/Cygwin). You can\nstill pipe the result into `sort` just the same.\n\nCiao,\nDscho\n\n> +sort |\n> +while read line\n> +do\n> +\techo \"\t\\\"$line\\\",\"\n> +done\n> +\n> +cat <<EOF\n> +};\n> +EOF\n> --\n> 2.24.1.735.g03f4e72817-goog\n>\n>\n"},{"id":"388303","messageId":"20191216213625.GE135450@google.com","threadId":"52442","inReplyTo":"xmqqv9qkhrtd.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 02/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T21:36:25Z","receivedAt":"2019-12-16T21:36:33Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 12:51:58PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\n> > builtin/clean.o, and builtin/config.o. This meant that help.o was\n> > unusable outside of the context of the main Git executable.\n> >\n> > To make help.o usable by other commands again, move list_config_help()\n> > into builtin/help.c (where it makes sense to assume other builtin libraries\n> > are present).\n> >\n> > When command-list.h is included but a member is not used, we start to\n> > hear a compiler warning. Since the config list is generated in a fairly\n> > different way than the command list, and since commands and config\n> > options are semantically different, move the config list into its own\n> > header and move the generator into its own script and build rule.\n> >\n> > Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> > ---\n> \n> OK.  Looks like a clean-up that is very worthy even without the\n> remainder of the topic.\n> \n> Thanks.\n\nOk. Are you going to take it on its own? If so, I'll be relying on two\nbranches in pu/ - what's the best way to let you know I need them both\nif/when I send another version of this chain?\n\n> \n> >  .gitignore             |  1 +\n> >  Makefile               | 16 ++++++--\n> >  builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n> >  generate-cmdlist.sh    | 19 ----------\n> >  generate-configlist.sh | 24 ++++++++++++\n> >  help.c                 | 85 -----------------------------------------\n> >  help.h                 |  1 -\n> >  7 files changed, 123 insertions(+), 109 deletions(-)\n> >  create mode 100755 generate-configlist.sh\n> >\n> > diff --git a/.gitignore b/.gitignore\n> > index 055a84c4a8..5dde2cc4c8 100644\n> > --- a/.gitignore\n> > +++ b/.gitignore\n> > @@ -189,6 +189,7 @@\n> >  /gitweb/gitweb.cgi\n> >  /gitweb/static/gitweb.js\n> >  /gitweb/static/gitweb.min.*\n> > +/config-list.h\n> >  /command-list.h\n> >  *.tar.gz\n> >  *.dsc\n> > diff --git a/Makefile b/Makefile\n> > index 9dff91436e..c49f55a521 100644\n> > --- a/Makefile\n> > +++ b/Makefile\n> > @@ -815,6 +815,7 @@ LIB_FILE = libgit.a\n> >  XDIFF_LIB = xdiff/lib.a\n> >  VCSSVN_LIB = vcs-svn/lib.a\n> >  \n> > +GENERATED_H += config-list.h\n> >  GENERATED_H += command-list.h\n> >  \n> >  LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n> > @@ -2127,7 +2128,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n> >  \n> >  help.sp help.s help.o: command-list.h\n> >  \n> > -builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n> > +builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n> >  builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n> >  \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n> >  \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n> > @@ -2147,6 +2148,12 @@ $(BUILT_INS): git$X\n> >  \tln -s $< $@ 2>/dev/null || \\\n> >  \tcp $< $@\n> >  \n> > +config-list.h: generate-configlist.sh\n> > +\n> > +config-list.h:\n> > +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n> > +\t\t>$@+ && mv $@+ $@\n> > +\n> >  command-list.h: generate-cmdlist.sh command-list.txt\n> >  \n> >  command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n> > @@ -2784,7 +2791,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n> >  .PHONY: sparse $(SP_OBJ)\n> >  sparse: $(SP_OBJ)\n> >  \n> > -GEN_HDRS := command-list.h unicode-width.h\n> > +GEN_HDRS := config-list.h command-list.h unicode-width.h\n> >  EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n> >  ifndef GCRYPT_SHA256\n> >  \tEXCEPT_HDRS += sha256/gcrypt.h\n> > @@ -2807,7 +2814,7 @@ hdr-check: $(HCO)\n> >  style:\n> >  \tgit clang-format --style file --diff --extensions c,h\n> >  \n> > -check: command-list.h\n> > +check: config-list.h command-list.h\n> >  \t@if sparse; \\\n> >  \tthen \\\n> >  \t\techo >&2 \"Use 'make sparse' instead\"; \\\n> > @@ -3110,7 +3117,8 @@ clean: profile-clean coverage-clean cocciclean\n> >  \t$(RM) $(HCC)\n> >  \t$(RM) -r bin-wrappers $(dep_dirs)\n> >  \t$(RM) -r po/build/\n> > -\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n> > +\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n> > +\t$(RM) $(ETAGS_TARGET) tags cscope*\n> >  \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n> >  \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n> >  \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\n> > diff --git a/builtin/help.c b/builtin/help.c\n> > index e5590d7787..1c5f2b9255 100644\n> > --- a/builtin/help.c\n> > +++ b/builtin/help.c\n> > @@ -8,6 +8,7 @@\n> >  #include \"parse-options.h\"\n> >  #include \"run-command.h\"\n> >  #include \"column.h\"\n> > +#include \"config-list.h\"\n> >  #include \"help.h\"\n> >  #include \"alias.h\"\n> >  \n> > @@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n> >  \tNULL\n> >  };\n> >  \n> > +struct slot_expansion {\n> > +\tconst char *prefix;\n> > +\tconst char *placeholder;\n> > +\tvoid (*fn)(struct string_list *list, const char *prefix);\n> > +\tint found;\n> > +};\n> > +\n> > +static void list_config_help(int for_human)\n> > +{\n> > +\tstruct slot_expansion slot_expansions[] = {\n> > +\t\t{ \"advice\", \"*\", list_config_advices },\n> > +\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n> > +\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n> > +\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n> > +\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n> > +\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n> > +\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n> > +\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n> > +\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> > +\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> > +\t\t{ NULL, NULL, NULL }\n> > +\t};\n> > +\tconst char **p;\n> > +\tstruct slot_expansion *e;\n> > +\tstruct string_list keys = STRING_LIST_INIT_DUP;\n> > +\tint i;\n> > +\n> > +\tfor (p = config_name_list; *p; p++) {\n> > +\t\tconst char *var = *p;\n> > +\t\tstruct strbuf sb = STRBUF_INIT;\n> > +\n> > +\t\tfor (e = slot_expansions; e->prefix; e++) {\n> > +\n> > +\t\t\tstrbuf_reset(&sb);\n> > +\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n> > +\t\t\tif (!strcasecmp(var, sb.buf)) {\n> > +\t\t\t\te->fn(&keys, e->prefix);\n> > +\t\t\t\te->found++;\n> > +\t\t\t\tbreak;\n> > +\t\t\t}\n> > +\t\t}\n> > +\t\tstrbuf_release(&sb);\n> > +\t\tif (!e->prefix)\n> > +\t\t\tstring_list_append(&keys, var);\n> > +\t}\n> > +\n> > +\tfor (e = slot_expansions; e->prefix; e++)\n> > +\t\tif (!e->found)\n> > +\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n> > +\t\t\t    e->prefix, e->placeholder);\n> > +\n> > +\tstring_list_sort(&keys);\n> > +\tfor (i = 0; i < keys.nr; i++) {\n> > +\t\tconst char *var = keys.items[i].string;\n> > +\t\tconst char *wildcard, *tag, *cut;\n> > +\n> > +\t\tif (for_human) {\n> > +\t\t\tputs(var);\n> > +\t\t\tcontinue;\n> > +\t\t}\n> > +\n> > +\t\twildcard = strchr(var, '*');\n> > +\t\ttag = strchr(var, '<');\n> > +\n> > +\t\tif (!wildcard && !tag) {\n> > +\t\t\tputs(var);\n> > +\t\t\tcontinue;\n> > +\t\t}\n> > +\n> > +\t\tif (wildcard && !tag)\n> > +\t\t\tcut = wildcard;\n> > +\t\telse if (!wildcard && tag)\n> > +\t\t\tcut = tag;\n> > +\t\telse\n> > +\t\t\tcut = wildcard < tag ? wildcard : tag;\n> > +\n> > +\t\t/*\n> > +\t\t * We may produce duplicates, but that's up to\n> > +\t\t * git-completion.bash to handle\n> > +\t\t */\n> > +\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n> > +\t}\n> > +\tstring_list_clear(&keys, 0);\n> > +}\n> > +\n> >  static enum help_format parse_help_format(const char *format)\n> >  {\n> >  \tif (!strcmp(format, \"man\"))\n> > diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> > index 71158f7d8b..45fecf8bdf 100755\n> > --- a/generate-cmdlist.sh\n> > +++ b/generate-cmdlist.sh\n> > @@ -76,23 +76,6 @@ print_command_list () {\n> >  \techo \"};\"\n> >  }\n> >  \n> > -print_config_list () {\n> > -\tcat <<EOF\n> > -static const char *config_name_list[] = {\n> > -EOF\n> > -\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> > -\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> > -\tsort |\n> > -\twhile read line\n> > -\tdo\n> > -\t\techo \"\t\\\"$line\\\",\"\n> > -\tdone\n> > -\tcat <<EOF\n> > -\tNULL,\n> > -};\n> > -EOF\n> > -}\n> > -\n> >  exclude_programs=\n> >  while test \"--exclude-program\" = \"$1\"\n> >  do\n> > @@ -113,5 +96,3 @@ echo\n> >  define_category_names \"$1\"\n> >  echo\n> >  print_command_list \"$1\"\n> > -echo\n> > -print_config_list\n> > diff --git a/generate-configlist.sh b/generate-configlist.sh\n> > new file mode 100755\n> > index 0000000000..eca6a00c30\n> > --- /dev/null\n> > +++ b/generate-configlist.sh\n> > @@ -0,0 +1,24 @@\n> > +#!/bin/sh\n> > +\n> > +echo \"/* Automatically generated by generate-configlist.sh */\"\n> > +echo\n> > +\n> > +print_config_list () {\n> > +\tcat <<EOF\n> > +static const char *config_name_list[] = {\n> > +EOF\n> > +\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> > +\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> > +\tsort |\n> > +\twhile read line\n> > +\tdo\n> > +\t\techo \"\t\\\"$line\\\",\"\n> > +\tdone\n> > +\tcat <<EOF\n> > +\tNULL,\n> > +};\n> > +EOF\n> > +}\n> > +\n> > +echo\n> > +print_config_list\n> > diff --git a/help.c b/help.c\n> > index cf67624a94..a21487db77 100644\n> > --- a/help.c\n> > +++ b/help.c\n> > @@ -407,91 +407,6 @@ void list_common_guides_help(void)\n> >  \tputchar('\\n');\n> >  }\n> >  \n> > -struct slot_expansion {\n> > -\tconst char *prefix;\n> > -\tconst char *placeholder;\n> > -\tvoid (*fn)(struct string_list *list, const char *prefix);\n> > -\tint found;\n> > -};\n> > -\n> > -void list_config_help(int for_human)\n> > -{\n> > -\tstruct slot_expansion slot_expansions[] = {\n> > -\t\t{ \"advice\", \"*\", list_config_advices },\n> > -\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n> > -\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n> > -\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n> > -\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n> > -\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n> > -\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n> > -\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n> > -\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> > -\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n> > -\t\t{ NULL, NULL, NULL }\n> > -\t};\n> > -\tconst char **p;\n> > -\tstruct slot_expansion *e;\n> > -\tstruct string_list keys = STRING_LIST_INIT_DUP;\n> > -\tint i;\n> > -\n> > -\tfor (p = config_name_list; *p; p++) {\n> > -\t\tconst char *var = *p;\n> > -\t\tstruct strbuf sb = STRBUF_INIT;\n> > -\n> > -\t\tfor (e = slot_expansions; e->prefix; e++) {\n> > -\n> > -\t\t\tstrbuf_reset(&sb);\n> > -\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n> > -\t\t\tif (!strcasecmp(var, sb.buf)) {\n> > -\t\t\t\te->fn(&keys, e->prefix);\n> > -\t\t\t\te->found++;\n> > -\t\t\t\tbreak;\n> > -\t\t\t}\n> > -\t\t}\n> > -\t\tstrbuf_release(&sb);\n> > -\t\tif (!e->prefix)\n> > -\t\t\tstring_list_append(&keys, var);\n> > -\t}\n> > -\n> > -\tfor (e = slot_expansions; e->prefix; e++)\n> > -\t\tif (!e->found)\n> > -\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n> > -\t\t\t    e->prefix, e->placeholder);\n> > -\n> > -\tstring_list_sort(&keys);\n> > -\tfor (i = 0; i < keys.nr; i++) {\n> > -\t\tconst char *var = keys.items[i].string;\n> > -\t\tconst char *wildcard, *tag, *cut;\n> > -\n> > -\t\tif (for_human) {\n> > -\t\t\tputs(var);\n> > -\t\t\tcontinue;\n> > -\t\t}\n> > -\n> > -\t\twildcard = strchr(var, '*');\n> > -\t\ttag = strchr(var, '<');\n> > -\n> > -\t\tif (!wildcard && !tag) {\n> > -\t\t\tputs(var);\n> > -\t\t\tcontinue;\n> > -\t\t}\n> > -\n> > -\t\tif (wildcard && !tag)\n> > -\t\t\tcut = wildcard;\n> > -\t\telse if (!wildcard && tag)\n> > -\t\t\tcut = tag;\n> > -\t\telse\n> > -\t\t\tcut = wildcard < tag ? wildcard : tag;\n> > -\n> > -\t\t/*\n> > -\t\t * We may produce duplicates, but that's up to\n> > -\t\t * git-completion.bash to handle\n> > -\t\t */\n> > -\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n> > -\t}\n> > -\tstring_list_clear(&keys, 0);\n> > -}\n> > -\n> >  static int get_alias(const char *var, const char *value, void *data)\n> >  {\n> >  \tstruct string_list *list = data;\n> > diff --git a/help.h b/help.h\n> > index 7a455beeb7..9071894e8c 100644\n> > --- a/help.h\n> > +++ b/help.h\n> > @@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n> >  void list_common_cmds_help(void);\n> >  void list_all_cmds_help(void);\n> >  void list_common_guides_help(void);\n> > -void list_config_help(int for_human);\n> >  \n> >  void list_all_main_cmds(struct string_list *list);\n> >  void list_all_other_cmds(struct string_list *list);\n"},{"id":"388305","messageId":"xmqqv9qfj4l7.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191216213625.GE135450@google.com","subject":"Re: [PATCH v4 02/15] help: move list_config_help to builtin/help","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-16T22:19:48Z","receivedAt":"2019-12-16T22:19:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n>> OK.  Looks like a clean-up that is very worthy even without the\n>> remainder of the topic.\n>> \n>> Thanks.\n>\n> Ok. Are you going to take it on its own?\n\nNot really.  Unless you abandon the rest of the topic, in which case\nit may be worth resurrecting this one on its own, that is.  But that\nis not what you plan to do anyway, so I expect to see it as part of\nan updated series ;-)\n"},{"id":"388306","messageId":"20191216223416.GF135450@google.com","threadId":"52442","inReplyTo":"xmqqv9qfj4l7.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 02/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T22:34:16Z","receivedAt":"2019-12-16T22:34:24Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Mon, Dec 16, 2019 at 02:19:48PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> >> OK.  Looks like a clean-up that is very worthy even without the\n> >> remainder of the topic.\n> >> \n> >> Thanks.\n> >\n> > Ok. Are you going to take it on its own?\n> \n> Not really.  Unless you abandon the rest of the topic, in which case\n> it may be worth resurrecting this one on its own, that is.  But that\n> is not what you plan to do anyway, so I expect to see it as part of\n> an updated series ;-)\n\nOk! That's fine and makes my life easier. Just making sure. :)\n\n - Emily\n"},{"id":"388308","messageId":"20191216223953.GG135450@google.com","threadId":"52442","inReplyTo":"xmqqimmjj557.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 06/15] bugreport: add glibc version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T22:39:53Z","receivedAt":"2019-12-16T22:40:01Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 01:18:44PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > To help pinpoint the source of a regression, it is useful to know the\n> > version of libc which the user's Git client was built with. Let's\n> > include it alongside the other versioning information, which is used to\n> > identify how the client was built.\n> >\n> > Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> > ---\n> >  bugreport.c | 5 +++++\n> >  1 file changed, 5 insertions(+)\n> \n> This is the first iffy one in the series.  It is unreasonable to\n> assume that we can dictate that Git can be built only on glibc\n> systems, no?\n> \n> Making this conditional, perhaps make \"bugreport.c\" depend on\n> \"extern void get_compiler_info(struct strbuf *sys_info)\" and require\n> the function to be defined in compat/; the glibc variant that uses\n> gnu_get_libc_version() would become just one of them.\n\nInteresting. This sounds like a good approach - thanks, I'll look into\nit.\n\n - Emily\n"},{"id":"388309","messageId":"20191216224928.GH135450@google.com","threadId":"52442","inReplyTo":"xmqqd0crj4qk.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 07/15] bugreport: add curl version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T22:49:28Z","receivedAt":"2019-12-16T22:50:03Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 01:27:31PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > It's possible for git-http* to be built separately from git; in that\n> > case we want to know what version of cURL is used by git-http*, not\n> > necessarily which version was present at git-bugreport's build time.\n> > So instead, ask git-http-fetch for the version information it knows\n> > about.\n> >\n> > git-http-fetch was chosen as git-http-backend was described as a\n> > server-side implementation, and as an accidental fetch in case of\n> > problems was considered less harmful than an accidental push.\n> >\n> > Since it could have been built at a different time, also report the\n> > version and built-from commit of git-http-fetch alongside the cURL info.\n> \n> One possible issue I have is that I was hoping that eventually we\n> can discard \"git http-fetch\" altogether sometime in the future.\n> Does anybody still use the dumb HTTP transport seriously?  \n\nOh, interesting. I was about to say, \"I still use it to fetch, when I\ndon't really care\" - but that isn't even true, as I fetch via https (and\nhave so much muscle memory to type https that I don't even notice).`\n\n> \n> And the first move in that direction would be to allow the system be\n> built without http-fetch, even if git-remote-curl (and its aliases)\n> would still be built to access smart-http transports.\n> \n> So, I am not sure.  This is just the matter of adding an out-of-line\n> hidden option used only for environment inspection, so if it can be\n> done to git-remote-curl, that would probably be much more future\n> proof.\n\nOk. I'll move it.\n\n> \n> > diff --git a/bugreport.c b/bugreport.c\n> > index af715dc157..f5598513d9 100644\n> > --- a/bugreport.c\n> > +++ b/bugreport.c\n> > @@ -5,6 +5,18 @@\n> >  #include \"time.h\"\n> >  #include \"help.h\"\n> >  #include <gnu/libc-version.h>\n> > +#include \"run-command.h\"\n> > +\n> > +static void get_http_version_info(struct strbuf *http_info)\n> > +{\n> > +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> > +\n> > +\targv_array_push(&cp.args, \"git\");\n> > +\targv_array_push(&cp.args, \"http-fetch\");\n> > +\targv_array_push(&cp.args, \"-V\");\n> > +\tif (capture_command(&cp, http_info, 0))\n> > +\t    strbuf_addstr(http_info, \"'git-http-fetch -V' not supported\\n\");\n> \n> OK.  We probably can also take the compile-time \"NO_CURL\" into account,\n> so that we can tell a misconfigured installation that wanted to have\n> CURL but failed to install a usable http-fetch and an installation\n> that deliberately omitted anything cURL?\n\nOh, interesting idea! I'll add that.\n\n> \n> >  static void get_system_info(struct strbuf *sys_info)\n> >  {\n> > @@ -32,6 +44,10 @@ static void get_system_info(struct strbuf *sys_info)\n> >  \tstrbuf_addstr(sys_info, \"glibc version: \");\n> >  \tstrbuf_addstr(sys_info, gnu_get_libc_version());\n> >  \tstrbuf_complete_line(sys_info);\n> > +\n> > +\tstrbuf_addstr(sys_info, \"git-http-fetch -V:\\n\");\n> > +\tget_http_version_info(sys_info);\n> > +\tstrbuf_complete_line(sys_info);\n> >  }\n> >  \n> >  static const char * const bugreport_usage[] = {\n> > diff --git a/http-fetch.c b/http-fetch.c\n> > index a32ac118d9..31844812a1 100644\n> > --- a/http-fetch.c\n> > +++ b/http-fetch.c\n> > @@ -3,9 +3,18 @@\n> >  #include \"exec-cmd.h\"\n> >  #include \"http.h\"\n> >  #include \"walker.h\"\n> > +#include \"version.h\"\n> >  \n> >  static const char http_fetch_usage[] = \"git http-fetch \"\n> > -\"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url\";\n> > +\"[-c] [-t] [-a] [-v] [-V] [--recover] [-w ref] [--stdin] commit-id url\";\n> > +\n> > +void NORETURN version_info()\n> \n> void NORETURN version_info(void)\n> \n> \n> > +{\n> > +\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n> > +\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n> > +\tprintf(\"curl version: %s\\n\", curl_version());\n> > +\texit(0);\n> > +}\n> >  \n> >  int cmd_main(int argc, const char **argv)\n> >  {\n> > @@ -26,6 +35,8 @@ int cmd_main(int argc, const char **argv)\n> >  \t\t} else if (argv[arg][1] == 'a') {\n> >  \t\t} else if (argv[arg][1] == 'v') {\n> >  \t\t\tget_verbosely = 1;\n> > +\t\t} else if (argv[arg][1] == 'V') {\n> > +\t\t\tversion_info();\n> >  \t\t} else if (argv[arg][1] == 'w') {\n> >  \t\t\twrite_ref = &argv[arg + 1];\n> >  \t\t\targ++;\n"},{"id":"388310","messageId":"20191216225207.GI135450@google.com","threadId":"52442","inReplyTo":"nycvar.QRO.7.76.6.1912152116030.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v4 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T22:52:07Z","receivedAt":"2019-12-16T22:52:14Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Sun, Dec 15, 2019 at 09:17:57PM +0100, Johannes Schindelin wrote:\n> Hi Emily,\n> \n> On Thu, 12 Dec 2019, Emily Shaffer wrote:\n> \n> > diff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\n> > new file mode 100755\n> > index 0000000000..06b8e0c3c4\n> > --- /dev/null\n> > +++ b/generate-bugreport-config-safelist.sh\n> > @@ -0,0 +1,22 @@\n> > +#!/bin/sh\n> > +\n> > +cat <<EOF\n> > +/* Automatically generated by bugreport-generate-config-safelist.sh */\n> > +\n> > +\n> > +static const char *bugreport_config_safelist[] = {\n> > +EOF\n> > +\n> > +# cat all regular files in Documentation/config\n> > +find Documentation/config -type f -exec cat {} \\; |\n> > +# print the command name which matches the bugreport-include macro\n> > +sed -n 's/^\\(.*\\) \\+bugreport:include.* ::$/\\1/p' |\n> \n> If you use `/  \"\\1\",/` as replacement, you can totally avoid that ugly\n> `while` loop (that is unfortunately quite slow in MSYS2/Cygwin). You can\n> still pipe the result into `sort` just the same.\n\nOooof. How embarrassing - I will do that.\n"},{"id":"388311","messageId":"20191216230124.GJ135450@google.com","threadId":"52442","inReplyTo":"xmqq7e2zhm0i.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T23:01:24Z","receivedAt":"2019-12-16T23:01:32Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 02:57:17PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > diff --git a/Makefile b/Makefile\n> > index c49f55a521..76dc51e2b1 100644\n> > --- a/Makefile\n> > +++ b/Makefile\n> > @@ -651,7 +651,7 @@ install-perl-script: $(SCRIPT_PERL_GEN)\n> >  install-python-script: $(SCRIPT_PYTHON_GEN)\n> >  \t$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n> >  \n> > -.PHONY: clean-perl-script clean-sh-script clean-python-script\n> > +.PHONY: clean-perl-script clean-sh-script clean-python-script clean-script-dependencies\n> >  clean-sh-script:\n> >  \t$(RM) $(SCRIPT_SH_GEN)\n> >  clean-perl-script:\n> > @@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n> >  \n> >  GENERATED_H += config-list.h\n> >  GENERATED_H += command-list.h\n> > +GENERATED_H += bugreport-config-safelist.h\n> \n> OK.\n> \n> >  LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n> >  \t$(FIND) . \\\n> > @@ -2161,6 +2162,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n> >  \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n> >  \t\tcommand-list.txt >$@+ && mv $@+ $@\n> >  \n> > +bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n> > +\n> > +bugreport-config-safelist.h: Documentation/config/*.txt\n> > +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n> > +\t\t>$@+ && mv $@+ $@\n> \n> OK.\n> \n> >  SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n> >  \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n> >  \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n> \n> But bugreport.o needs this *.h file generated before a compiler\n> attempts to produce it out of bugreport.c; that dependency is\n> missing from this update to the Makefile.\n\nHm. Somewhere I misformatted my commits, then. My goal was to add the\nnew header here, but not add it as a dependency to anybody; then, in the\nnext commit, add it as a dependency to git-bugreport and start to use it\n(commit 1: make the thing; commit 2: use the thing). But now when I look\nat the next commit, I don't see a Makefile change. So I missed something\nwhile I was shuffling around fixups.  Thanks for noticing.\n\n> \n> > @@ -2791,7 +2798,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n> >  .PHONY: sparse $(SP_OBJ)\n> >  sparse: $(SP_OBJ)\n> >  \n> > -GEN_HDRS := config-list.h command-list.h unicode-width.h\n> > +GEN_HDRS := config-list.h command-list.h unicode-width.h bugreport-config-safelist.h\n> >  EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n> >  ifndef GCRYPT_SHA256\n> >  \tEXCEPT_HDRS += sha256/gcrypt.h\n> > @@ -3117,7 +3124,8 @@ clean: profile-clean coverage-clean cocciclean\n> >  \t$(RM) $(HCC)\n> >  \t$(RM) -r bin-wrappers $(dep_dirs)\n> >  \t$(RM) -r po/build/\n> > -\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n> > +\t$(RM) *.pyc *.pyo */*.pyc */*.pyo\n> > +\t$(RM) config-list.h command-list.h bugreport-config-safelist.h\n> \n> It is kind of sad that GEN_HDRS defines the list of build artifact\n> that we should be able to clean, and then we manually list them to\n> be removed here independently.  Can we fix it up too?\n\nYeah, I can do that. I thought so too when I was updating this.\n\nI *think* what happened is that when I split config-list away (in the\nearleir commit in this chain) I didn't notice that command-list.h was\nalready in GEN_HDRS, and instead just grepped Makefile for\n\"command-list.h\" and added config-list.h next to it. So I'll try to fix\nit much earlier, in that commit, and then simply add to the appropriate\nvariables in this commit.\n\n> \n> We probably clean up the build/update procedure around unicode-width.h\n> before we can do so, probably.  It may be generatable using contrib/\n> script, but as far as our normal build is concerned, it is a tracked\n> source and not part of the build byproducts, so we probably would\n> want to remove it from GEN_HDRS.  When that happens, we can $(RM)\n> all of the $(GEN_HDRS) in the \"clean\" target.\n\nNoted. Thanks.\n\n - Emily\n"},{"id":"388312","messageId":"20191216234036.GK135450@google.com","threadId":"52442","inReplyTo":"xmqq4ky3j3w4.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T23:40:36Z","receivedAt":"2019-12-16T23:40:44Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 01:45:47PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > Teach bugreport to gather the values of config options which are present\n> > in 'bugreport-config-safelist.h'.\n> >\n> > Many config options are sensitive, and many Git add-ons use config\n> > options which git-core does not know about; it is better only to gather\n> > config options which we know to be safe, rather than excluding options\n> > which we know to be unsafe.\n> >\n> > Taking the build-time generated array and putting it into a set saves us\n> > time - since git_config_bugreport() is called for every option the user\n> > has configured, performing option lookup in constant time is a useful\n> > optimization.\n> \n> Interesting.  I actually was expecting the look-up to go the other\n> way around.  We know the safe keys, so iterate over them and grab\n> their values, if defined.  No need for hashes or anything, but just\n> a simple linear list of safe stuff.\n\nHm. Without looking at the code, I said to myself,\n\"repo_config_get_value() will open all the available config files to\nfind the resolved value, so I don't want to do n*4 file open/closes, I\nonly want to do 4 total.\"\n\nNow I look at the code and see that the configs are already being read\ninto a hashset before now. So you're right that it doesn't make sense\nfor me to do it this way....\n\n> \n> But that is too simple-minded.  If we wanted to safelist foo.*.bar,\n> where '*' can be anything, walking on the list of safe variables\n> would not work.  We must have a hash table that knows \"foo.*.bar\" is\n> allowed, and while walking all the configuration keys, when we see\n> foo.a.bar, we consult \"foo.*.bar\" as well as \"foo.a.bar\" to see if\n> it is whitelisted, or something like that.\n\n...unless we want to use wildcards like you suggest.\n\nBut I'm not sure it's a good idea. I envision someone writing another\nGit add-on, which offers someone to specify \"user.password\" and\nautomagically do some Bitbucket interaction, or something. (An extreme\nand misguided example, but I hope the point remains.) Then if I say,\n\"all the user.* configs I can see in 'git help config' are safe, so I\nwill just safelist user.*,\" I'm not accounting for this other tool's\nknown configs which are a superset of what Git knows and expects.\n\nThe point of this safelist-generation exercise is to avoid accidentally\nprinting some sensitive user config, and the point of using a safelist\ninstead of a blocklist is to avoid printing a third-party config we\ndidn't know about (or messing up our pattern matching). So I suggest we\navoid pattern matching entirely.\n\n> \n> But then I am not sure if this implementation does something like\n> this for three-level names.  If not, I do not see much point in use\n> of the hash there either.\n> \n> Puzzled.\n\nI'd prefer to solve it by iterating over the compile-time-generated\nsafelist using get_config_value_multi(), which I clock at O(n) for n =\nsafelist length: performing n calls to an O(1) hashset lookup. That\nsaves us the O(n*log(n)) hashset population, and the implementation of\nYet Another Set in the source.\n\nThanks.\n\n - Emily\n"},{"id":"388313","messageId":"20191216235131.GL135450@google.com","threadId":"52442","inReplyTo":"xmqqzhfvhp8w.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 11/15] bugreport: collect list of populated hooks","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T23:51:31Z","receivedAt":"2019-12-16T23:51:40Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 01:47:27PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > +\t/*\n> > +\t * Doesn't look like there is a list of all possible hooks; so below is\n> > +\t * a transcription of `git help hook`.\n> > +\t */\n> \n> We probably would want to employ technique similar to what you used\n> for the list of safe configuration we saw in an earlier patch in the\n> series.  What's not even documented is not worth reporting ;-)\n\nI somewhat slightly would rather not, since I hope to include a list of\nthe available hooks in my work with git-hook:\nhttps://lore.kernel.org/20191211205114.GD107889@google.com\n\nIt's true that the way this patch is written now is prone to bitrot.\nIt's also true that I could win the lottery tomorrow and never finish my\nhopes of git-hook implementation. And it's finally true that I don't\nwant to write a fourth build-time-generated header which scrapes docs,\nespecially if I also plan to delete it two months from now.\n\nI wonder whether a better approach might be to drop hook support\nentirely here, and add it later on when this particular bit of tech debt\n(no canonical list of hook names) is solved, one way or another.\n\nAnother approach may be to just list all contents of $(core.hookdir)/\nwhich doesn't end in \".sample\", which is what the bash first attempt of\nbugreport did. This does mean that those who have something like:\n\n  .git/hooks/\n    pre-commit\n    pre-commit.d/\n\n  pre-commit:\n    sh pre-commit.d/a\n    sh pre-commit.d/b\n\nwill have their multihook config exposed, although the contents of those\nhooks won't be.\n\nI'm interested to know everyone else's opinion, because mine is biased\nby my hope that I can solve all the world's problems with git-hook ;)\n\n - Emily\n"},{"id":"388314","messageId":"20191216235421.GM135450@google.com","threadId":"52442","inReplyTo":"xmqqv9qjhp28.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 12/15] bugreport: count loose objects","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T23:54:21Z","receivedAt":"2019-12-16T23:54:29Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 01:51:27PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > The number of unpacked objects in a user's repository may help us\n> > understand the root of the problem they're seeing, especially if a\n> > command is running unusually slowly.\n> >\n> > Rather than directly invoking 'git-count-objects', which may sometimes\n> > fail unexpectedly on Git for Windows, manually count the contents of\n> > .git/objects.\n> \n> Is for_each_loose_object() or for_each_loose_file_in_objdir() not\n> sufficient?  We really do *not* want a redundant implementation of\n> something we already use elsewhere in the system, especially for the\n> purpose of this program, because you would end up reporting what you\n> computed in a way that may be quite different from what the rest of\n> the system that is actually used by the end users computes.\n> \nOh, thanks for the pointer. That looks sufficient - I will investigate\nthe differences between the two and stop filesystem browsing by hand in\nthis case.\n\n - Emily\n"},{"id":"388315","messageId":"20191216235615.GN135450@google.com","threadId":"52442","inReplyTo":"xmqqr217houg.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 13/15] bugreport: add packed object summary","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-16T23:56:15Z","receivedAt":"2019-12-16T23:56:22Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 01:56:07PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > Alongside the list of loose objects, it's useful to see the list of\n> > object packs as well. It can help us to examine what Git did and did not\n> > pack.\n> \n> Not exactly the same comment, but is in the same spirit, as the\n> previous step applies to this one.\n> \n> Would it be too much work to libify the bulk of cmd_count_objects()\n> that computes numbers, making the cmd_count_objects() into a thin\n> wrapper that calls the libified \"counter/collector\" function and\n> prints the resulting numbers received from it?\n> \n> That way, the get_packed_object_summary() can be another consumer       \n> of the same \"counter/collector\" function, no?\n\nThat sounds like a good approach. Will do.\n\n> \n> > Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> > ---\n> >  bugreport.c | 31 +++++++++++++++++++++++++++++++\n> >  1 file changed, 31 insertions(+)\n> >\n> > diff --git a/bugreport.c b/bugreport.c\n> > index 3abb83d77f..992d8f9de7 100644\n> > --- a/bugreport.c\n> > +++ b/bugreport.c\n> > @@ -234,6 +234,34 @@ static void get_loose_object_summary(struct strbuf *obj_info) {\n> >  \tstrbuf_release(&dirpath);\n> >  }\n> >  \n> > +static void get_packed_object_summary(struct strbuf *obj_info)\n> > +{\n> > +\tstruct strbuf dirpath = STRBUF_INIT;\n> > +\tstruct dirent *d;\n> > +\tDIR *dir = NULL;\n> > +\n> > +\tstrbuf_addstr(&dirpath, get_object_directory());\n> > +\tstrbuf_complete(&dirpath, '/');\n> > +\tstrbuf_addstr(&dirpath, \"pack/\");\n> > +\n> > +\tdir = opendir(dirpath.buf);\n> > +\tif (!dir) {\n> > +\t\tstrbuf_addf(obj_info, \"could not open packed object directory '%s'\\n\",\n> > +\t\t\t    dirpath.buf);\n> > +\t\tstrbuf_release(&dirpath);\n> > +\t\treturn;\n> > +\t}\n> > +\n> > +\twhile ((d = readdir(dir))) {\n> > +\t\tstrbuf_addbuf(obj_info, &dirpath);\n> > +\t\tstrbuf_addstr(obj_info, d->d_name);\n> > +\t\tstrbuf_complete_line(obj_info);\n> > +\t}\n> > +\n> > +\tclosedir(dir);\n> > +\tstrbuf_release(&dirpath);\n> > +}\n> > +\n> >  static const char * const bugreport_usage[] = {\n> >  \tN_(\"git bugreport [-o|--output <file>]\"),\n> >  \tNULL\n> > @@ -307,6 +335,9 @@ int cmd_main(int argc, const char **argv)\n> >  \tget_header(&buffer, \"Loose Object Counts\");\n> >  \tget_loose_object_summary(&buffer);\n> >  \n> > +\tget_header(&buffer, \"Packed Object Summary\");\n> > +\tget_packed_object_summary(&buffer);\n> > +\n> >  \treport = fopen_for_writing(report_path.buf);\n> >  \tstrbuf_write(&buffer, report);\n> >  \tfclose(report);\n"},{"id":"388319","messageId":"20191217004127.GP135450@google.com","threadId":"52442","inReplyTo":"20191216230124.GJ135450@google.com","subject":"Re: [PATCH v4 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-17T00:41:27Z","receivedAt":"2019-12-17T00:41:36Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Mon, Dec 16, 2019 at 03:01:24PM -0800, Emily Shaffer wrote:\n> On Fri, Dec 13, 2019 at 02:57:17PM -0800, Junio C Hamano wrote:\n> > Emily Shaffer <emilyshaffer@google.com> writes:\n> > \n> > > diff --git a/Makefile b/Makefile\n> > > index c49f55a521..76dc51e2b1 100644\n> > > --- a/Makefile\n> > > +++ b/Makefile\n> > > @@ -651,7 +651,7 @@ install-perl-script: $(SCRIPT_PERL_GEN)\n> > >  install-python-script: $(SCRIPT_PYTHON_GEN)\n> > >  \t$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n> > >  \n> > > -.PHONY: clean-perl-script clean-sh-script clean-python-script\n> > > +.PHONY: clean-perl-script clean-sh-script clean-python-script clean-script-dependencies\n> > >  clean-sh-script:\n> > >  \t$(RM) $(SCRIPT_SH_GEN)\n> > >  clean-perl-script:\n> > > @@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n> > >  \n> > >  GENERATED_H += config-list.h\n> > >  GENERATED_H += command-list.h\n> > > +GENERATED_H += bugreport-config-safelist.h\n> > \n> > OK.\n> > \n> > >  LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n> > >  \t$(FIND) . \\\n> > > @@ -2161,6 +2162,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n> > >  \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n> > >  \t\tcommand-list.txt >$@+ && mv $@+ $@\n> > >  \n> > > +bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n> > > +\n> > > +bugreport-config-safelist.h: Documentation/config/*.txt\n> > > +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n> > > +\t\t>$@+ && mv $@+ $@\n> > \n> > OK.\n> > \n> > >  SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n> > >  \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n> > >  \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n> > \n> > But bugreport.o needs this *.h file generated before a compiler\n> > attempts to produce it out of bugreport.c; that dependency is\n> > missing from this update to the Makefile.\n> \n> Hm. Somewhere I misformatted my commits, then. My goal was to add the\n> new header here, but not add it as a dependency to anybody; then, in the\n> next commit, add it as a dependency to git-bugreport and start to use it\n> (commit 1: make the thing; commit 2: use the thing). But now when I look\n> at the next commit, I don't see a Makefile change. So I missed something\n> while I was shuffling around fixups.  Thanks for noticing.\n> \n> > \n> > > @@ -2791,7 +2798,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n> > >  .PHONY: sparse $(SP_OBJ)\n> > >  sparse: $(SP_OBJ)\n> > >  \n> > > -GEN_HDRS := config-list.h command-list.h unicode-width.h\n> > > +GEN_HDRS := config-list.h command-list.h unicode-width.h bugreport-config-safelist.h\n> > >  EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n> > >  ifndef GCRYPT_SHA256\n> > >  \tEXCEPT_HDRS += sha256/gcrypt.h\n> > > @@ -3117,7 +3124,8 @@ clean: profile-clean coverage-clean cocciclean\n> > >  \t$(RM) $(HCC)\n> > >  \t$(RM) -r bin-wrappers $(dep_dirs)\n> > >  \t$(RM) -r po/build/\n> > > -\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n> > > +\t$(RM) *.pyc *.pyo */*.pyc */*.pyo\n> > > +\t$(RM) config-list.h command-list.h bugreport-config-safelist.h\n> > \n> > It is kind of sad that GEN_HDRS defines the list of build artifact\n> > that we should be able to clean, and then we manually list them to\n> > be removed here independently.  Can we fix it up too?\n> \n> Yeah, I can do that. I thought so too when I was updating this.\n> \n> I *think* what happened is that when I split config-list away (in the\n> earleir commit in this chain) I didn't notice that command-list.h was\n> already in GEN_HDRS, and instead just grepped Makefile for\n> \"command-list.h\" and added config-list.h next to it. So I'll try to fix\n> it much earlier, in that commit, and then simply add to the appropriate\n> variables in this commit.\n> \n> > \n> > We probably clean up the build/update procedure around unicode-width.h\n> > before we can do so, probably.  It may be generatable using contrib/\n> > script, but as far as our normal build is concerned, it is a tracked\n> > source and not part of the build byproducts, so we probably would\n> > want to remove it from GEN_HDRS.  When that happens, we can $(RM)\n> > all of the $(GEN_HDRS) in the \"clean\" target.\n> \n> Noted. Thanks.\n\nAh, after I sent this mail I saw your patch. For those playing along at\nhome, https://lore.kernel.org/xmqq1rt7hkp6.fsf@gitster-ct.c.googlers.com\n\nWill review.\n\n - Emily\n"},{"id":"388380","messageId":"xmqqfthij1ac.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20191216234036.GK135450@google.com","subject":"Re: [PATCH v4 10/15] bugreport: add config values from safelist","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-17T17:43:23Z","receivedAt":"2019-12-17T17:43:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n>> But that is too simple-minded.  If we wanted to safelist foo.*.bar,\n>> where '*' can be anything, walking on the list of safe variables\n>> would not work.  We must have a hash table that knows \"foo.*.bar\" is\n>> allowed, and while walking all the configuration keys, when we see\n>> foo.a.bar, we consult \"foo.*.bar\" as well as \"foo.a.bar\" to see if\n>> it is whitelisted, or something like that.\n>\n> ...unless we want to use wildcards like you suggest.\n>\n> But I'm not sure it's a good idea. I envision someone writing another\n> Git add-on, which offers someone to specify \"user.password\" ...\n\nWildcarding the leaf level of two (or for that matter three) level\nnames like \"user.*\" in your example is of course a nonsense way to\nuse the safelist.  But think about three-level names where the\nsecond level is designed to be used for user-supplied token to give\nthings of similar nature a name the user can use to distinguish\nthings.  If remote.origin.url is worth reporting, wouldn't\nremote.upstream.url also be?  Shouldn't remote.*.url be the way to\nsay \"the URL field for each and every remote is a safe thing to\nreport\" in the safelist?\n"},{"id":"388386","messageId":"nycvar.QRO.7.76.6.1912171936450.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20191213004312.169753-10-emilyshaffer@google.com","subject":"Re: [PATCH v4 09/15] bugreport: generate config safelist based on docs","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-12-17T18:38:37Z","receivedAt":"2019-12-17T18:38:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 12 Dec 2019, Emily Shaffer wrote:\n\n> diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\n> index d906a00803..750bdff9af 100644\n> --- a/Documentation/asciidoctor-extensions.rb\n> +++ b/Documentation/asciidoctor-extensions.rb\n> @@ -37,6 +37,10 @@ module Git\n>            output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n>          end\n>          output\n> +\n> +    class BugReportProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n> +      def process(parent, action, attrs)\n> +        \"\"\n\nThe Azure Pipeline fails on this hunk, saying:\n\n/usr/bin/asciidoctor: /home/vsts/work/1/s/Documentation/asciidoctor-extensions.rb:41: class definition in method body (SyntaxError)\n/home/vsts/work/1/s/Documentation/asciidoctor-extensions.rb:55: syntax error, unexpected end-of-input, expecting keyword_end\n\nSee\nhttps://dev.azure.com/gitgitgadget/git/_build/results?buildId=23830&view=logs&jobId=253e5128-1058-5bd4-fdf1-9b556d3207f8&j=253e5128-1058-5bd4-fdf1-9b556d3207f8&t=95c65aec-3627-54dc-fc17-47625f123bb3\nfor details.\n\nCiao,\nDscho\n\n>        end\n>      end\n>    end\n> @@ -45,4 +49,7 @@ end\n>  Asciidoctor::Extensions.register do\n>    inline_macro Git::Documentation::LinkGitProcessor, :linkgit\n>    postprocessor Git::Documentation::DocumentPostProcessor\n> +  # The bugreport macro does nothing as far as rendering is\n> +  # concerned -- we just grep for it in the sources.\n> +  inline_macro Git::Documentation::BugReportProcessor, :bugreport\n>  end\n> diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\n> index 0006faf800..92f5082013 100644\n> --- a/Documentation/config/sendemail.txt\n> +++ b/Documentation/config/sendemail.txt\n> @@ -1,63 +1,63 @@\n> -sendemail.identity::\n> +sendemail.identity bugreport:exclude[x] ::\n>  \tA configuration identity. When given, causes values in the\n>  \t'sendemail.<identity>' subsection to take precedence over\n>  \tvalues in the 'sendemail' section. The default identity is\n>  \tthe value of `sendemail.identity`.\n>\n> -sendemail.smtpEncryption::\n> +sendemail.smtpEncryption bugreport:include[x] ::\n>  \tSee linkgit:git-send-email[1] for description.  Note that this\n>  \tsetting is not subject to the 'identity' mechanism.\n>\n> -sendemail.smtpssl (deprecated)::\n> +sendemail.smtpssl (deprecated) bugreport:exclude[x] ::\n>  \tDeprecated alias for 'sendemail.smtpEncryption = ssl'.\n>\n> -sendemail.smtpsslcertpath::\n> +sendemail.smtpsslcertpath bugreport:exclude[x] ::\n>  \tPath to ca-certificates (either a directory or a single file).\n>  \tSet it to an empty string to disable certificate verification.\n>\n> -sendemail.<identity>.*::\n> +sendemail.<identity>.* bugreport:exclude[x] ::\n>  \tIdentity-specific versions of the 'sendemail.*' parameters\n>  \tfound below, taking precedence over those when this\n>  \tidentity is selected, through either the command-line or\n>  \t`sendemail.identity`.\n>\n> -sendemail.aliasesFile::\n> -sendemail.aliasFileType::\n> -sendemail.annotate::\n> -sendemail.bcc::\n> -sendemail.cc::\n> -sendemail.ccCmd::\n> -sendemail.chainReplyTo::\n> -sendemail.confirm::\n> -sendemail.envelopeSender::\n> -sendemail.from::\n> -sendemail.multiEdit::\n> -sendemail.signedoffbycc::\n> -sendemail.smtpPass::\n> -sendemail.suppresscc::\n> -sendemail.suppressFrom::\n> -sendemail.to::\n> -sendemail.tocmd::\n> -sendemail.smtpDomain::\n> -sendemail.smtpServer::\n> -sendemail.smtpServerPort::\n> -sendemail.smtpServerOption::\n> -sendemail.smtpUser::\n> -sendemail.thread::\n> -sendemail.transferEncoding::\n> -sendemail.validate::\n> -sendemail.xmailer::\n> +sendemail.aliasesFile bugreport:exclude[x] ::\n> +sendemail.aliasFileType bugreport:exclude[x] ::\n> +sendemail.annotate bugreport:include[x] ::\n> +sendemail.bcc bugreport:include[x] ::\n> +sendemail.cc bugreport:include[x] ::\n> +sendemail.ccCmd bugreport:include[x] ::\n> +sendemail.chainReplyTo bugreport:include[x] ::\n> +sendemail.confirm bugreport:include[x] ::\n> +sendemail.envelopeSender bugreport:include[x] ::\n> +sendemail.from bugreport:include[x] ::\n> +sendemail.multiEdit bugreport:include[x] ::\n> +sendemail.signedoffbycc bugreport:include[x] ::\n> +sendemail.smtpPass bugreport:exclude[x] ::\n> +sendemail.suppresscc bugreport:include[x] ::\n> +sendemail.suppressFrom bugreport:include[x] ::\n> +sendemail.to bugreport:include[x] ::\n> +sendemail.tocmd bugreport:include[x] ::\n> +sendemail.smtpDomain bugreport:include[x] ::\n> +sendemail.smtpServer bugreport:include[x] ::\n> +sendemail.smtpServerPort bugreport:include[x] ::\n> +sendemail.smtpServerOption bugreport:include[x] ::\n> +sendemail.smtpUser bugreport:exclude[x] ::\n> +sendemail.thread bugreport:include[x] ::\n> +sendemail.transferEncoding bugreport:include[x] ::\n> +sendemail.validate bugreport:include[x] ::\n> +sendemail.xmailer bugreport:include[x] ::\n>  \tSee linkgit:git-send-email[1] for description.\n>\n> -sendemail.signedoffcc (deprecated)::\n> +sendemail.signedoffcc (deprecated) bugreport:exclude[x] ::\n>  \tDeprecated alias for `sendemail.signedoffbycc`.\n>\n> -sendemail.smtpBatchSize::\n> +sendemail.smtpBatchSize bugreport:include[x] ::\n>  \tNumber of messages to be sent per connection, after that a relogin\n>  \twill happen.  If the value is 0 or undefined, send all messages in\n>  \tone connection.\n>  \tSee also the `--batch-size` option of linkgit:git-send-email[1].\n>\n> -sendemail.smtpReloginDelay::\n> +sendemail.smtpReloginDelay bugreport:include[x] ::\n>  \tSeconds wait before reconnecting to smtp server.\n>  \tSee also the `--relogin-delay` option of linkgit:git-send-email[1].\n> diff --git a/Makefile b/Makefile\n> index c49f55a521..76dc51e2b1 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -651,7 +651,7 @@ install-perl-script: $(SCRIPT_PERL_GEN)\n>  install-python-script: $(SCRIPT_PYTHON_GEN)\n>  \t$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'\n>\n> -.PHONY: clean-perl-script clean-sh-script clean-python-script\n> +.PHONY: clean-perl-script clean-sh-script clean-python-script clean-script-dependencies\n>  clean-sh-script:\n>  \t$(RM) $(SCRIPT_SH_GEN)\n>  clean-perl-script:\n> @@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n>\n>  GENERATED_H += config-list.h\n>  GENERATED_H += command-list.h\n> +GENERATED_H += bugreport-config-safelist.h\n>\n>  LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n>  \t$(FIND) . \\\n> @@ -2161,6 +2162,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n>  \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n>  \t\tcommand-list.txt >$@+ && mv $@+ $@\n>\n> +bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n> +\n> +bugreport-config-safelist.h: Documentation/config/*.txt\n> +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n> +\t\t>$@+ && mv $@+ $@\n> +\n>  SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n>  \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n>  \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n> @@ -2791,7 +2798,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n>  .PHONY: sparse $(SP_OBJ)\n>  sparse: $(SP_OBJ)\n>\n> -GEN_HDRS := config-list.h command-list.h unicode-width.h\n> +GEN_HDRS := config-list.h command-list.h unicode-width.h bugreport-config-safelist.h\n>  EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%\n>  ifndef GCRYPT_SHA256\n>  \tEXCEPT_HDRS += sha256/gcrypt.h\n> @@ -3117,7 +3124,8 @@ clean: profile-clean coverage-clean cocciclean\n>  \t$(RM) $(HCC)\n>  \t$(RM) -r bin-wrappers $(dep_dirs)\n>  \t$(RM) -r po/build/\n> -\t$(RM) *.pyc *.pyo */*.pyc */*.pyo config-list.h command-list.h\n> +\t$(RM) *.pyc *.pyo */*.pyc */*.pyo\n> +\t$(RM) config-list.h command-list.h bugreport-config-safelist.h\n>  \t$(RM) $(ETAGS_TARGET) tags cscope*\n>  \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n>  \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n> diff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\n> new file mode 100755\n> index 0000000000..06b8e0c3c4\n> --- /dev/null\n> +++ b/generate-bugreport-config-safelist.sh\n> @@ -0,0 +1,22 @@\n> +#!/bin/sh\n> +\n> +cat <<EOF\n> +/* Automatically generated by bugreport-generate-config-safelist.sh */\n> +\n> +\n> +static const char *bugreport_config_safelist[] = {\n> +EOF\n> +\n> +# cat all regular files in Documentation/config\n> +find Documentation/config -type f -exec cat {} \\; |\n> +# print the command name which matches the bugreport-include macro\n> +sed -n 's/^\\(.*\\) \\+bugreport:include.* ::$/\\1/p' |\n> +sort |\n> +while read line\n> +do\n> +\techo \"\t\\\"$line\\\",\"\n> +done\n> +\n> +cat <<EOF\n> +};\n> +EOF\n> --\n> 2.24.1.735.g03f4e72817-goog\n>\n>\n>\n"},{"id":"388389","messageId":"nycvar.QRO.7.76.6.1912171941451.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20191213004312.169753-4-emilyshaffer@google.com","subject":"Re: [PATCH v4 03/15] bugreport: gather git version and build info","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-12-17T18:45:12Z","receivedAt":"2019-12-17T18:45:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 12 Dec 2019, Emily Shaffer wrote:\n\n> diff --git a/help.c b/help.c\n> index a21487db77..a43693fca5 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)\n>  \texit(1);\n>  }\n>\n> +void list_version_info(struct strbuf *buf, int build_options)\n> +{\n> +\tstrbuf_reset(buf);\n> +\t/*\n> +\t * The format of this string should be kept stable for compatibility\n> +\t * with external projects that rely on the output of \"git version\".\n> +\t *\n> +\t * Always show the version, even if other options are given.\n> +\t */\n> +\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n> +\n> +\tif (build_options) {\n> +\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n> +\t\tif (git_built_from_commit_string[0])\n> +\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n> +\t\t\t       git_built_from_commit_string);\n> +\t\telse\n> +\t\t\tstrbuf_addf(buf, \"no commit associated with this build\\n\");\n\nThe \"StaticAnalysis\" job of the Azure Pipeline is not happy with this,\nclaiming that this should be an `strbuf_addstr()` call instead. For\ndetails, see:\n\nhttps://dev.azure.com/gitgitgadget/8fc4a374-71dc-4558-a5ea-dd1c081ea621/_apis/build/builds/23830/logs/68\n\nCiao,\nDscho\n\n> +\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n> +\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n> +\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n> +\t}\n> +}\n> +\n>  int cmd_version(int argc, const char **argv, const char *prefix)\n>  {\n> +\tstruct strbuf buf = STRBUF_INIT;\n>  \tint build_options = 0;\n>  \tconst char * const usage[] = {\n>  \t\tN_(\"git version [<options>]\"),\n> @@ -637,25 +662,9 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n>\n>  \targc = parse_options(argc, argv, prefix, options, usage, 0);\n>\n> -\t/*\n> -\t * The format of this string should be kept stable for compatibility\n> -\t * with external projects that rely on the output of \"git version\".\n> -\t *\n> -\t * Always show the version, even if other options are given.\n> -\t */\n> -\tprintf(\"git version %s\\n\", git_version_string);\n> +\tlist_version_info(&buf, build_options);\n> +\tprintf(\"%s\", buf.buf);\n>\n> -\tif (build_options) {\n> -\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n> -\t\tif (git_built_from_commit_string[0])\n> -\t\t\tprintf(\"built from commit: %s\\n\",\n> -\t\t\t       git_built_from_commit_string);\n> -\t\telse\n> -\t\t\tprintf(\"no commit associated with this build\\n\");\n> -\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n> -\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n> -\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n> -\t}\n>  \treturn 0;\n>  }\n>\n> diff --git a/help.h b/help.h\n> index 9071894e8c..54f6b5f793 100644\n> --- a/help.h\n> +++ b/help.h\n> @@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n>  void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n>  int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n>  void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n> +void list_version_info(struct strbuf *buf, int build_options);\n>\n>  /*\n>   * call this to die(), when it is suspected that the user mistyped a\n> --\n> 2.24.1.735.g03f4e72817-goog\n>\n>\n>\n"},{"id":"388390","messageId":"nycvar.QRO.7.76.6.1912171946260.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20191213004312.169753-8-emilyshaffer@google.com","subject":"Re: [PATCH v4 07/15] bugreport: add curl version","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-12-17T18:47:43Z","receivedAt":"2019-12-17T18:48:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 12 Dec 2019, Emily Shaffer wrote:\n\n> diff --git a/http-fetch.c b/http-fetch.c\n> index a32ac118d9..31844812a1 100644\n> --- a/http-fetch.c\n> +++ b/http-fetch.c\n> @@ -3,9 +3,18 @@\n>  #include \"exec-cmd.h\"\n>  #include \"http.h\"\n>  #include \"walker.h\"\n> +#include \"version.h\"\n>\n>  static const char http_fetch_usage[] = \"git http-fetch \"\n> -\"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url\";\n> +\"[-c] [-t] [-a] [-v] [-V] [--recover] [-w ref] [--stdin] commit-id url\";\n> +\n> +void NORETURN version_info()\n\nPretty much all the builds in\nhttps://dev.azure.com/gitgitgadget/git/_build/results?buildId=23830&view=logs&jobId=253e5128-1058-5bd4-fdf1-9b556d3207f8&j=fd490c07-0b22-5182-fac9-6d67fe1e939b&t=ce91d5d6-0c55-50f5-8ab9-6695c03ab102\nfail because this function definition needs `(void)` instead of `()`.\n\nCiao,\nDscho\n\n> +{\n> +\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n> +\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n> +\tprintf(\"curl version: %s\\n\", curl_version());\n> +\texit(0);\n> +}\n>\n>  int cmd_main(int argc, const char **argv)\n>  {\n> @@ -26,6 +35,8 @@ int cmd_main(int argc, const char **argv)\n>  \t\t} else if (argv[arg][1] == 'a') {\n>  \t\t} else if (argv[arg][1] == 'v') {\n>  \t\t\tget_verbosely = 1;\n> +\t\t} else if (argv[arg][1] == 'V') {\n> +\t\t\tversion_info();\n>  \t\t} else if (argv[arg][1] == 'w') {\n>  \t\t\twrite_ref = &argv[arg + 1];\n>  \t\t\targ++;\n> --\n> 2.24.1.735.g03f4e72817-goog\n>\n>\n>\n"},{"id":"388406","messageId":"xmqqfthig07m.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"nycvar.QRO.7.76.6.1912171941451.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v4 03/15] bugreport: gather git version and build info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-12-17T20:34:53Z","receivedAt":"2019-12-17T20:34:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> +\tif (build_options) {\n>> +\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n>> +\t\tif (git_built_from_commit_string[0])\n>> +\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n>> +\t\t\t       git_built_from_commit_string);\n>> +\t\telse\n>> +\t\t\tstrbuf_addf(buf, \"no commit associated with this build\\n\");\n>\n> The \"StaticAnalysis\" job of the Azure Pipeline is not happy with this,\n> claiming that this should be an `strbuf_addstr()` call instead.\n\nYou mean the \"else\" clause, right?  That feels similar to say\n\n\tprintf(\"Hello world\\n\");\n\nshould better be written as\n\n\tfputs(\"Hello world\\n\", stdout);\n\nwhich I do not agree with at all.  IOW, I view the distinction more\nlike \"once it is written one way or the other way, it is not worth\nspending bits and braincycles to see if it is worth changing it\"\nkind of minor stylistic preference.\n\n\n"},{"id":"388603","messageId":"20191220012524.GB227872@google.com","threadId":"52442","inReplyTo":"xmqqfthig07m.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 03/15] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-20T01:25:24Z","receivedAt":"2019-12-20T01:25:32Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Dec 17, 2019 at 12:34:53PM -0800, Junio C Hamano wrote:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> +\tif (build_options) {\n> >> +\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n> >> +\t\tif (git_built_from_commit_string[0])\n> >> +\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n> >> +\t\t\t       git_built_from_commit_string);\n> >> +\t\telse\n> >> +\t\t\tstrbuf_addf(buf, \"no commit associated with this build\\n\");\n> >\n> > The \"StaticAnalysis\" job of the Azure Pipeline is not happy with this,\n> > claiming that this should be an `strbuf_addstr()` call instead.\n> \n> You mean the \"else\" clause, right?  That feels similar to say\n> \n> \tprintf(\"Hello world\\n\");\n> \n> should better be written as\n> \n> \tfputs(\"Hello world\\n\", stdout);\n> \n> which I do not agree with at all.  IOW, I view the distinction more\n> like \"once it is written one way or the other way, it is not worth\n> spending bits and braincycles to see if it is worth changing it\"\n> kind of minor stylistic preference.\n\nI think I side with Junio here, although it's true that when\nstrbuf_addstr() exists it doesn't make that much sense to use\nstrbuf_addf(). Since there's some other comments, though, I'll change\nthis too to make your CI shut up. :)\n\n - Emily\n"},{"id":"388604","messageId":"20191220014619.GC227872@google.com","threadId":"52442","inReplyTo":"xmqqr218hr56.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 03/15] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2019-12-20T01:46:19Z","receivedAt":"2019-12-20T01:46:26Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Dec 13, 2019 at 01:06:29PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > Knowing which version of Git a user has and how it was built allows us\n> > to more precisely pin down the circumstances when a certain issue\n> > occurs, so teach bugreport how to tell us the same output as 'git\n> > version --build-options'.\n> >\n> > It's not ideal to directly call 'git version --build-options' because\n> > that output goes to stdout. Instead, wrap the version string in a helper\n> > within help.[ch] library, and call that helper from within the bugreport\n> > library.\n> \n> Move to strbuf() from stdio makes sense.  \n> \n> > +\t// add other contents\n> \n> Style.\n\nSure, dropped this entirely. I think with the helpers the code is\nself-documenting there.\n\n> \n> > diff --git a/help.h b/help.h\n> > index 9071894e8c..54f6b5f793 100644\n> > --- a/help.h\n> > +++ b/help.h\n> > @@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n> >  void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n> >  int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n> \n> \n> Many new helpers are called get_frotz(), but only one among these is\n> called list_version_info().  I do not think the naming of the\n> get_*() ones, that are private to the bugreport tool, matters that\n> much, but unlike \"list_commands()\" whose purpose is to list the\n> commands ;-), the new function does not list versions---it just\n> gives information about a single version which is the one that is\n> being run, so perhaps it is a misnomer.\n\nHm, sure. I renamed it to get_version_info(); I had named it list_*\nbecause all the other helpers in help.h are named list_*, and it does\nprint more than one piece of info. But I do see your point (all the info\nis about the same version) so I've renamed it.\n\n> \n> >  void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n> > +void list_version_info(struct strbuf *buf, int build_options);\n> \n> It is not clear to the readers build_options is a boolean that\n> tells the function to include (or not to include) build options.\n> Perhaps rename it to \"int show_build_options\" or something?\n\nAgree, done.\n"},{"id":"389043","messageId":"nycvar.QRO.7.76.6.1912292115530.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20191213004312.169753-11-emilyshaffer@google.com","subject":"Re: [PATCH v4 10/15] bugreport: add config values from safelist","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-12-29T20:17:20Z","receivedAt":"2019-12-29T20:17:38Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 12 Dec 2019, Emily Shaffer wrote:\n\n> diff --git a/bugreport.c b/bugreport.c\n> index 759cc0b0f8..1fca28f0b9 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -6,6 +6,9 @@\n>  #include \"help.h\"\n>  #include <gnu/libc-version.h>\n>  #include \"run-command.h\"\n> +#include \"config.h\"\n> +#include \"bugreport-config-safelist.h\"\n> +#include \"khash.h\"\n\nSeems that this patch makes things fail in the CI build\n(https://dev.azure.com/gitgitgadget/git/_build/results?buildId=23830&view=results):\n\n-- snipsnap --\nbugreport.c:10:10: fatal error: 'bugreport-config-safelist.h' file not found\n#include \"bugreport-config-safelist.h\"\n         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n1 error generated.\nMakefile:2395: recipe for target 'bugreport.o' failed\nmake: *** [bugreport.o] Error 1\nmake: *** Waiting for unfinished jobs....\n\n"},{"id":"389562","messageId":"20200110020529.GB1216@pug.qqx.org","threadId":"52442","inReplyTo":"20191213004312.169753-6-emilyshaffer@google.com","subject":"Re: [PATCH v4 05/15] bugreport: add uname info","fromName":"Aaron Schrab","fromEmail":"aaron@schrab.com","sentAt":"2020-01-10T02:05:29Z","receivedAt":"2020-01-10T02:11:09Z","isPatch":true,"sender":{"key":"aaron@schrab.com","avatar":"https://avatars.githubusercontent.com/u/39620?v=4"},"body":"At 16:43 -0800 12 Dec 2019, Emily Shaffer <emilyshaffer@google.com> wrote:\n>The contents of uname() can give us some insight into what sort of\n>system the user is running on, and help us replicate their setup if need\n>be. The domainname field is not guaranteed to be available, so don't\n>collect it.\n\nThe manpage on Linux says that it's a GNU extension; on Mac OS it isn't \nmentioned. So it would be more accurate to say that it's known not to be \navailable on many systems rather than just not being guaranteed.\n\nBesides that I think in some cases it may be considered sensitive \ninformation, so another reason to not include it. Perhaps even worthy of \nbeing mentioned as the primary reason.\n\n>+\t\t\t    uname_info.nodename,\n\nI think in some cases this could also be considered as sensitive \ninformation, and is unlikely to help in diagnosing problems.  So I'd \nmove to exclude this as well.\n"},{"id":"390326","messageId":"20200124032905.GA37541@google.com","threadId":"52442","inReplyTo":"xmqqfthij1ac.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:29:05Z","receivedAt":"2020-01-24T03:29:13Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Dec 17, 2019 at 09:43:23AM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> >> But that is too simple-minded.  If we wanted to safelist foo.*.bar,\n> >> where '*' can be anything, walking on the list of safe variables\n> >> would not work.  We must have a hash table that knows \"foo.*.bar\" is\n> >> allowed, and while walking all the configuration keys, when we see\n> >> foo.a.bar, we consult \"foo.*.bar\" as well as \"foo.a.bar\" to see if\n> >> it is whitelisted, or something like that.\n> >\n> > ...unless we want to use wildcards like you suggest.\n> >\n> > But I'm not sure it's a good idea. I envision someone writing another\n> > Git add-on, which offers someone to specify \"user.password\" ...\n> \n> Wildcarding the leaf level of two (or for that matter three) level\n> names like \"user.*\" in your example is of course a nonsense way to\n> use the safelist.  But think about three-level names where the\n> second level is designed to be used for user-supplied token to give\n> things of similar nature a name the user can use to distinguish\n> things.  If remote.origin.url is worth reporting, wouldn't\n> remote.upstream.url also be?  Shouldn't remote.*.url be the way to\n> say \"the URL field for each and every remote is a safe thing to\n> report\" in the safelist?\n\nBah, somehow this mail slipped through the cracks for me.\n\nWhen you put it that way, I see how it can be useful. Although I admit\nto fatigue on this patchset and now I'm hesitant about feature creep. :)\n\nI'm going to send the reroll for v5 as I have it, not having seen this\nmail, and think more about how I'd approach wildcarding in the middle\nlike this. I want to take a look at the other configs which use a middle\nlevel as a user token and try to reason about whether we ought to be\ncollecting them. I'll hope to report back sooner (or later).\n\n - Emily\n"},{"id":"390327","messageId":"20200124033436.81097-1-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20191213004312.169753-1-emilyshaffer@google.com","subject":"[PATCH v5 00/15] add git-bugreport tool","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:21Z","receivedAt":"2020-01-24T03:35:22Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nThis topic branch depends on the patch mailed in\nlore.kernel.org/git/20191211233820.185153-1-emilyshaffer@google.com in order to\ndisplay scopes for configs gathered during \"bugreport: add config values from\nsafelist\".\n\nI'll summarize v4-v5. Since v4 has languished for some time, I don't\nthink an interdiff is too helpful, so I won't include one. Bonus, the\ncode is much simplified from some suggestions from Junio on how to\ninspect objects, so I hope it's easy to review anyways.\n\nThroughout, did some style changes away from C++ bad habits. Otherwise,\nas listed:\n\nEmily Shaffer (15):\n  bugreport: add tool to generate debugging info\n    (no change)\n  help: move list_config_help to builtin/help\n    Changed to agree with f3719846134\n\n  bugreport: gather git version and build info\n    Style only\n\n  help: add shell-path to --build-options\n    (no change)\n\n  bugreport: add uname info\n    Removed nodename for privacy reasons\n\n  bugreport: add compiler info\n    Moved glibc tattling into compat/.\n\n    I appreciate a close look at this one - I think I understood the\n    right way to go about a compat/ util but it's the first one I've\n    done.\n\n  bugreport: add curl version\n    Moved curl tattling from git-http-fetch into git-remote-curl\n\n  bugreport: include user interactive shell\n    Stop depending on a compiler quirk to save us from segfault\n\n  bugreport: generate config safelist based on docs\n    Changed to agree with f3719846134\n    Cleaned up script a little\n\n  bugreport: add config values from safelist\n    Made git-bugreport dependent on generated safelist header\n\n  bugreport: collect list of populated hooks\n    No change.\n    Per https://lore.kernel.org/git/20191216235131.GL135450@google.com,\n    should we even keep this patch?\n\n  bugreport: count loose objects\n    Use helpers from object-store.h instead of manually walking the\n    filesystem.\n\n  bugreport: add packed object summary\n    Use helpers from object-store.h instead of manually walking the\n    filesystem.\n\n  bugreport: list contents of $OBJDIR/info\n    (no change)\n\n  bugreport: summarize contents of alternates file\n    Rephrase commit message to explain why I can't use the helpers in\n    object-store.h.\n\n\nThanks.\n - Emily\n\n\n .gitignore                              |   3 +\n Documentation/asciidoc.conf             |   8 +\n Documentation/asciidoctor-extensions.rb |   7 +\n Documentation/config/sendemail.txt      |  68 ++--\n Documentation/git-bugreport.txt         |  43 +++\n Makefile                                |  25 +-\n bugreport.c                             | 427 ++++++++++++++++++++++++\n builtin/help.c                          |  86 +++++\n compat/compiler.h                       |  24 ++\n generate-bugreport-config-safelist.sh   |  22 ++\n generate-cmdlist.sh                     |  19 --\n generate-configlist.sh                  |  24 ++\n help.c                                  | 133 ++------\n help.h                                  |   2 +-\n remote-curl.c                           |   8 +\n t/t0091-bugreport.sh                    |  41 +++\n 16 files changed, 780 insertions(+), 160 deletions(-)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100644 compat/compiler.h\n create mode 100755 generate-bugreport-config-safelist.sh\n create mode 100755 generate-configlist.sh\n create mode 100755 t/t0091-bugreport.sh\n\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390328","messageId":"20200124033436.81097-2-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 01/15] bugreport: add tool to generate debugging info","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:22Z","receivedAt":"2020-01-24T03:35:22Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nTeach Git how to prompt the user for a good bug report: reproduction\nsteps, expected behavior, and actual behavior. Later, Git can learn how\nto collect some diagnostic information from the repository.\n\nIf users can send us a well-written bug report which contains diagnostic\ninformation we would otherwise need to ask the user for, we can reduce\nthe number of question-and-answer round trips between the reporter and\nthe Git contributor.\n\nUsers may also wish to send a report like this to their local \"Git\nexpert\" if they have put their repository into a state they are confused\nby.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                      |  1 +\n Documentation/git-bugreport.txt | 43 ++++++++++++++++++++\n Makefile                        |  5 +++\n bugreport.c                     | 69 +++++++++++++++++++++++++++++++++\n t/t0091-bugreport.sh            | 41 ++++++++++++++++++++\n 5 files changed, 159 insertions(+)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex aebe7c0908..ca301bc890 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -25,6 +25,7 @@\n /git-bisect--helper\n /git-blame\n /git-branch\n+/git-bugreport\n /git-bundle\n /git-cat-file\n /git-check-attr\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..75f0c80acf\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,43 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [-o | --output <path>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+The following information is captured automatically:\n+\n+ - Git version (`git version --build-options`)\n+ - Machine information (`uname -a`)\n+ - Versions of various dependencies\n+ - Git config contents (`git config --show-origin --list`)\n+ - The names of all configured git-hooks in `.git/hooks/`\n+\n+OPTIONS\n+-------\n+-o [<path>]::\n+--output [<path>]::\n+\tPlace the resulting bug report file in <path> instead of the root of the\n+\tGit repository.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex 09f98b777c..f271619371 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -2450,6 +2451,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\ndiff --git a/bugreport.c b/bugreport.c\nnew file mode 100644\nindex 0000000000..5495b31674\n--- /dev/null\n+++ b/bugreport.c\n@@ -0,0 +1,69 @@\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output <file>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to send.\\n\");\n+\n+\tstrbuf_addstr(template, template_text);\n+\treturn 0;\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tFILE *report;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"\", bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\tif (option_output) {\n+\t\tstrbuf_addstr(&report_path, option_output);\n+\t\tstrbuf_complete(&report_path, '/');\n+\t}\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, \"%F\", gmtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\n+\tget_bug_template(&buffer);\n+\n+\treport = fopen_for_writing(report_path.buf);\n+\tstrbuf_write(&buffer, report);\n+\tfclose(report);\n+\n+\tlaunch_editor(report_path.buf, NULL, NULL);\n+\treturn 0;\n+}\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..6eb2ee4f66\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,41 @@\n+#!/bin/bash\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+check_all_headers_populated() {\n+\twhile read -r line; do\n+\t\tif [$(grep $HEADER_PATTERN $line)]; then\n+\t\t\tread -r nextline\n+\t\t\tif [-z $nextline]; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\tgit bugreport &&\n+\tcheck_all_headers_populated <git-bugreport-* &&\n+\trm git-bugreport-*\n+'\n+\n+test_expect_success '--output puts the report in the provided dir' '\n+\tmkdir foo/ &&\n+\tgit bugreport -o foo/ &&\n+\ttest -f foo/git-bugreport-* &&\n+\trm -fr foo/\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\tgrep usage output &&\n+\ttest ! -f git-bugreport-*\n+'\n+\n+test_done\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390329","messageId":"20200124033436.81097-5-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 04/15] help: add shell-path to --build-options","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:25Z","receivedAt":"2020-01-24T03:35:22Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nIt may be useful to know which shell Git was built to try to point to,\nin the event that shell-based Git commands are failing. $SHELL_PATH is\nset during the build and used to launch the manpage viewer, as well as\nby git-compat-util.h, and it's used during tests. 'git version\n--build-options' is encouraged for use in bug reports, so it makes sense\nto include this information there.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n help.c | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/help.c b/help.c\nindex 156a6cdea3..d3f941824f 100644\n--- a/help.c\n+++ b/help.c\n@@ -642,6 +642,7 @@ void get_version_info(struct strbuf *buf, int show_build_options)\n \t\t\tstrbuf_addstr(buf, \"no commit associated with this build\\n\");\n \t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n \t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\tstrbuf_addf(buf, \"shell-path: %s\\n\", SHELL_PATH);\n \t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n \t}\n }\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390330","messageId":"20200124033436.81097-4-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 03/15] bugreport: gather git version and build info","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:24Z","receivedAt":"2020-01-24T03:35:22Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nKnowing which version of Git a user has and how it was built allows us\nto more precisely pin down the circumstances when a certain issue\noccurs, so teach bugreport how to tell us the same output as 'git\nversion --build-options'.\n\nIt's not ideal to directly call 'git version --build-options' because\nthat output goes to stdout. Instead, wrap the version string in a helper\nwithin help.[ch] library, and call that helper from within the bugreport\nlibrary.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 22 +++++++++++++++++++++-\n help.c      | 47 +++++++++++++++++++++++++++++------------------\n help.h      |  1 +\n 3 files changed, 51 insertions(+), 19 deletions(-)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 5495b31674..b1a5a279ac 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,8 +1,20 @@\n-#include \"builtin.h\"\n+#include \"cache.h\"\n #include \"parse-options.h\"\n #include \"stdio.h\"\n #include \"strbuf.h\"\n #include \"time.h\"\n+#include \"help.h\"\n+\n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\tstruct strbuf version_info = STRBUF_INIT;\n+\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, \"git version:\\n\");\n+\tget_version_info(&version_info, 1);\n+\tstrbuf_addbuf(sys_info, &version_info);\n+\tstrbuf_complete_line(sys_info);\n+}\n \n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n@@ -32,6 +44,11 @@ static int get_bug_template(struct strbuf *template)\n \treturn 0;\n }\n \n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n int cmd_main(int argc, const char **argv)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n@@ -60,6 +77,9 @@ int cmd_main(int argc, const char **argv)\n \n \tget_bug_template(&buffer);\n \n+\tget_header(&buffer, \"System Info\");\n+\tget_system_info(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\ndiff --git a/help.c b/help.c\nindex a21487db77..156a6cdea3 100644\n--- a/help.c\n+++ b/help.c\n@@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void get_version_info(struct strbuf *buf, int show_build_options)\n+{\n+\tstrbuf_reset(buf);\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (show_build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addstr(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -637,25 +662,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tget_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n+\n+\tstrbuf_release(&buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 9071894e8c..500521b908 100644\n--- a/help.h\n+++ b/help.h\n@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void get_version_info(struct strbuf *buf, int show_build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390331","messageId":"20200124033436.81097-3-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 02/15] help: move list_config_help to builtin/help","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:23Z","receivedAt":"2020-01-24T03:35:22Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nStarting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\nbuiltin/clean.o, and builtin/config.o. This meant that help.o was\nunusable outside of the context of the main Git executable.\n\nTo make help.o usable by other commands again, move list_config_help()\ninto builtin/help.c (where it makes sense to assume other builtin libraries\nare present).\n\nWhen command-list.h is included but a member is not used, we start to\nhear a compiler warning. Since the config list is generated in a fairly\ndifferent way than the command list, and since commands and config\noptions are semantically different, move the config list into its own\nheader and move the generator into its own script and build rule.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore             |  1 +\n Makefile               | 13 +++++--\n builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n generate-cmdlist.sh    | 19 ----------\n generate-configlist.sh | 24 ++++++++++++\n help.c                 | 85 -----------------------------------------\n help.h                 |  1 -\n 7 files changed, 121 insertions(+), 108 deletions(-)\n create mode 100755 generate-configlist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ca301bc890..d89bf9e11e 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -190,6 +190,7 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex f271619371..a01a050aa3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -815,6 +815,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n@@ -2129,7 +2130,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2149,6 +2150,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2786,7 +2793,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%\n+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n endif\n@@ -2808,7 +2815,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..eca6a00c30\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,24 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\twhile read line\n+\tdo\n+\t\techo \"\t\\\"$line\\\",\"\n+\tdone\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/help.c b/help.c\nindex cf67624a94..a21487db77 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\ndiff --git a/help.h b/help.h\nindex 7a455beeb7..9071894e8c 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390332","messageId":"20200124033436.81097-6-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 05/15] bugreport: add uname info","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:26Z","receivedAt":"2020-01-24T03:35:27Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nThe contents of uname() can give us some insight into what sort of\nsystem the user is running on, and help us replicate their setup if need\nbe. The domainname field is not guaranteed to be available, so don't\ncollect it.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 12 ++++++++++++\n 1 file changed, 12 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex b1a5a279ac..720c91e1bd 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -8,12 +8,24 @@\n static void get_system_info(struct strbuf *sys_info)\n {\n \tstruct strbuf version_info = STRBUF_INIT;\n+\tstruct utsname uname_info;\n \n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, \"git version:\\n\");\n \tget_version_info(&version_info, 1);\n \tstrbuf_addbuf(sys_info, &version_info);\n \tstrbuf_complete_line(sys_info);\n+\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname -a: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, \"uname() failed with code %d\\n\", errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390333","messageId":"20200124033436.81097-7-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 06/15] bugreport: add compiler info","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:27Z","receivedAt":"2020-01-24T03:35:27Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nTo help pinpoint the source of a regression, it is useful to know some\ninfo about the compiler which the user's Git client was built with. By\nadding a generic get_compiler_info() in 'compat/' we can choose which\nrelevant information to share per compiler; to get started, let's\ndemonstrate the version of glibc if the user built with 'gcc'.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c       |  5 +++++\n compat/compiler.h | 24 ++++++++++++++++++++++++\n 2 files changed, 29 insertions(+)\n create mode 100644 compat/compiler.h\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 720c91e1bd..818ccb385c 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"time.h\"\n #include \"help.h\"\n+#include \"compat/compiler.h\"\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -26,6 +27,10 @@ static void get_system_info(struct strbuf *sys_info)\n \t\t\t    uname_info.release,\n \t\t\t    uname_info.version,\n \t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, \"compiler info: \");\n+\tget_compiler_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/compat/compiler.h b/compat/compiler.h\nnew file mode 100644\nindex 0000000000..bda5098e1b\n--- /dev/null\n+++ b/compat/compiler.h\n@@ -0,0 +1,24 @@\n+#ifndef COMPILER_H\n+#define COMPILER_H\n+\n+#include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+\n+#ifdef __GLIBC__\n+#include <gnu/libc-version.h>\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tstrbuf_addf(info, \"glibc: %s\", gnu_get_libc_version());\n+}\n+\n+#else\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tstrbuf_addstr(info, \"get_compiler_info() not implemented\");\n+}\n+\n+#endif\n+\n+#endif /* COMPILER_H */\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390334","messageId":"20200124033436.81097-8-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 07/15] bugreport: add curl version","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:28Z","receivedAt":"2020-01-24T03:35:32Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nIt's possible for git-remote-curl to be built separately from git; in that\ncase we want to know what version of cURL is used by git-remote-curl, not\nnecessarily which version was present at git-bugreport's build time.\nSo instead, ask git-remote-curl for the version information it knows\nabout.\n\nFor longevity purposes, invoke the alias \"git-remote-https\" instead of\n\"git-remote-http\".\n\nSince it could have been built at a different time, also report the\nversion and built-from commit of git-remote-curl alongside the cURL info.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c   | 16 ++++++++++++++++\n remote-curl.c |  8 ++++++++\n 2 files changed, 24 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 818ccb385c..73f6d39517 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -5,6 +5,18 @@\n #include \"time.h\"\n #include \"help.h\"\n #include \"compat/compiler.h\"\n+#include \"run-command.h\"\n+\n+static void get_curl_version_info(struct strbuf *curl_info)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\targv_array_push(&cp.args, \"git\");\n+\targv_array_push(&cp.args, \"remote-https\");\n+\targv_array_push(&cp.args, \"--build-info\");\n+\tif (capture_command(&cp, curl_info, 0))\n+\t    strbuf_addstr(curl_info, \"'git-remote-https --build-info' not supported\\n\");\n+}\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -31,6 +43,10 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_addstr(sys_info, \"compiler info: \");\n \tget_compiler_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n+\n+\tstrbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n+\tget_curl_version_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 350d92a074..c590fbfae3 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -17,6 +17,7 @@\n #include \"protocol.h\"\n #include \"quote.h\"\n #include \"transport.h\"\n+#include \"version.h\"\n \n static struct remote *remote;\n /* always ends with a trailing slash */\n@@ -1374,6 +1375,13 @@ int cmd_main(int argc, const char **argv)\n \tstring_list_init(&options.deepen_not, 1);\n \tstring_list_init(&options.push_options, 1);\n \n+\tif (!strcmp(\"--build-info\", argv[1])) {\n+\t\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n+\t\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n+\t\tprintf(\"curl version: %s\\n\", curl_version());\n+\t\treturn 0;\n+\t}\n+\n \t/*\n \t * Just report \"remote-curl\" here (folding all the various aliases\n \t * (\"git-remote-http\", \"git-remote-https\", and etc.) here since they\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390335","messageId":"20200124033436.81097-9-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 08/15] bugreport: include user interactive shell","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:29Z","receivedAt":"2020-01-24T03:35:33Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nIt's possible a user may complain about the way that Git interacts with\ntheir interactive shell, e.g. autocompletion or shell prompt. In that\ncase, it's useful for us to know which shell they're using\ninteractively.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 73f6d39517..07b84b9c94 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -22,6 +22,7 @@ static void get_system_info(struct strbuf *sys_info)\n {\n \tstruct strbuf version_info = STRBUF_INIT;\n \tstruct utsname uname_info;\n+\tchar *shell = NULL;\n \n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, \"git version:\\n\");\n@@ -44,6 +45,10 @@ static void get_system_info(struct strbuf *sys_info)\n \tget_compiler_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n \n+\tshell = getenv(\"SHELL\");\n+\tstrbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n+\t\t    shell ? shell : \"(NULL)\");\n+\n \tstrbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n \tget_curl_version_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390336","messageId":"20200124033436.81097-10-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 09/15] bugreport: generate config safelist based on docs","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:30Z","receivedAt":"2020-01-24T03:35:34Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nAdd a new step to the build to generate a safelist of git-config\nvariables which are appropriate to include in the output of\ngit-bugreport. New variables can be added to the safelist by annotating\ntheir documentation in Documentation/config with the\n\"bugreport\" macro, which is recognized by AsciiDoc and\nAsciiDoctor.\n\nSome configs are private in nature, and can contain remote URLs,\npasswords, or other sensitive information. In the event that a user\ndoesn't notice their information while reviewing a bugreport, that user\nmay leak their credentials to other individuals, mailing lists, or bug\ntracking tools inadvertently. Heuristic blocklisting of configuration\nkeys is imperfect and prone to false negatives; given the nature of the\ninformation which can be leaked, a safelist is more reliable.\n\nIn order to prevent staleness of the safelist, add a mechanism to\ngenerate the safelist from annotations in the config documentation,\nwhere contributors are already used to documenting their new config\nkeys.\n\nImplement a new no-op \"bugreport\" macro for use as\n\"bugreport:include[x]\" to annotate the config keys that should be\nincluded in the automatically generated safelist. Use \"exclude\" for the\nothers.\n\nWith Asciidoctor, it's ok to say \"bugreport:include[]\", but AsciiDoc\nseems to want something between the brackets. A bit unfortunate, but\nnot a huge problem -- we'll just provide an \"x\".\n\n\"doc-diff\" reports that this macro doesn't render at all. That is,\nthese are both empty after this commit:\n\n  cd Documentation\n  ./doc-diff --asciidoctor :/\"bugreport: add tool\" HEAD\n  ./doc-diff --asciidoc    :/\"bugreport: add tool\" HEAD\n\nDiffing the rendered HTML shows that there is some small amount of\nwhitespace and comments added. That shouldn't be a problem.\n\nWe could perhaps let the implementation verify that the \"action\" is one\nof \"include\" and \"exclude\". For the Asciidoctor implementation that\nshould be straightforward, but for AsciiDoc I don't immediately know how\nto do it. Anyway, if someone stumbles on the keyboard and writes\n\"bugreport:icndule\", they'll \"only\" miss out on the config key being\nincluded in the safelist. If this were a blocklist, the consequences of\na misspelled target could be a lot more severe.\n\nAdditionally, add annotations to the sendemail config documentation in\norder to demonstrate a proof of concept.\n\nHelped-by: Martin Ågren <martin.agren@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                              |  1 +\n Documentation/asciidoc.conf             |  8 +++\n Documentation/asciidoctor-extensions.rb |  7 +++\n Documentation/config/sendemail.txt      | 68 ++++++++++++-------------\n Makefile                                |  7 +++\n generate-bugreport-config-safelist.sh   | 17 +++++++\n 6 files changed, 74 insertions(+), 34 deletions(-)\n create mode 100755 generate-bugreport-config-safelist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex d89bf9e11e..bd2f49b996 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -192,6 +192,7 @@\n /gitweb/static/gitweb.min.*\n /config-list.h\n /command-list.h\n+/bugreport-config-safelist.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\nindex 8fc4b67081..5d5359fcf9 100644\n--- a/Documentation/asciidoc.conf\n+++ b/Documentation/asciidoc.conf\n@@ -6,9 +6,13 @@\n #\n # Show Git link as: <command>(<section>); if section is defined, else just show\n # the command.\n+#\n+# The bugreport macro does nothing as far as rendering is\n+# concerned -- we just grep for it in the sources.\n \n [macros]\n (?su)[\\\\]?(?P<name>linkgit):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n+(?su)[\\\\]?(?P<name>bugreport):(?P<action>\\S*?)\\[(?P<attrlist>.*?)\\]=\n \n [attributes]\n asterisk=&#42;\n@@ -28,6 +32,8 @@ ifdef::backend-docbook[]\n {0#<citerefentry>}\n {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n {0#</citerefentry>}\n+[bugreport-inlinemacro]\n+{0#}\n endif::backend-docbook[]\n \n ifdef::backend-docbook[]\n@@ -94,4 +100,6 @@ ifdef::backend-xhtml11[]\n git-relative-html-prefix=\n [linkgit-inlinemacro]\n <a href=\"{git-relative-html-prefix}{target}.html\">{target}{0?({0})}</a>\n+[bugreport-inlinemacro]\n+<!-- -->\n endif::backend-xhtml11[]\ndiff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\nindex d906a00803..750bdff9af 100644\n--- a/Documentation/asciidoctor-extensions.rb\n+++ b/Documentation/asciidoctor-extensions.rb\n@@ -37,6 +37,10 @@ module Git\n           output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n         end\n         output\n+\n+    class BugReportProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n+      def process(parent, action, attrs)\n+        \"\"\n       end\n     end\n   end\n@@ -45,4 +49,7 @@ end\n Asciidoctor::Extensions.register do\n   inline_macro Git::Documentation::LinkGitProcessor, :linkgit\n   postprocessor Git::Documentation::DocumentPostProcessor\n+  # The bugreport macro does nothing as far as rendering is\n+  # concerned -- we just grep for it in the sources.\n+  inline_macro Git::Documentation::BugReportProcessor, :bugreport\n end\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 0006faf800..92f5082013 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -1,63 +1,63 @@\n-sendemail.identity::\n+sendemail.identity bugreport:exclude[x] ::\n \tA configuration identity. When given, causes values in the\n \t'sendemail.<identity>' subsection to take precedence over\n \tvalues in the 'sendemail' section. The default identity is\n \tthe value of `sendemail.identity`.\n \n-sendemail.smtpEncryption::\n+sendemail.smtpEncryption bugreport:include[x] ::\n \tSee linkgit:git-send-email[1] for description.  Note that this\n \tsetting is not subject to the 'identity' mechanism.\n \n-sendemail.smtpssl (deprecated)::\n+sendemail.smtpssl (deprecated) bugreport:exclude[x] ::\n \tDeprecated alias for 'sendemail.smtpEncryption = ssl'.\n \n-sendemail.smtpsslcertpath::\n+sendemail.smtpsslcertpath bugreport:exclude[x] ::\n \tPath to ca-certificates (either a directory or a single file).\n \tSet it to an empty string to disable certificate verification.\n \n-sendemail.<identity>.*::\n+sendemail.<identity>.* bugreport:exclude[x] ::\n \tIdentity-specific versions of the 'sendemail.*' parameters\n \tfound below, taking precedence over those when this\n \tidentity is selected, through either the command-line or\n \t`sendemail.identity`.\n \n-sendemail.aliasesFile::\n-sendemail.aliasFileType::\n-sendemail.annotate::\n-sendemail.bcc::\n-sendemail.cc::\n-sendemail.ccCmd::\n-sendemail.chainReplyTo::\n-sendemail.confirm::\n-sendemail.envelopeSender::\n-sendemail.from::\n-sendemail.multiEdit::\n-sendemail.signedoffbycc::\n-sendemail.smtpPass::\n-sendemail.suppresscc::\n-sendemail.suppressFrom::\n-sendemail.to::\n-sendemail.tocmd::\n-sendemail.smtpDomain::\n-sendemail.smtpServer::\n-sendemail.smtpServerPort::\n-sendemail.smtpServerOption::\n-sendemail.smtpUser::\n-sendemail.thread::\n-sendemail.transferEncoding::\n-sendemail.validate::\n-sendemail.xmailer::\n+sendemail.aliasesFile bugreport:exclude[x] ::\n+sendemail.aliasFileType bugreport:exclude[x] ::\n+sendemail.annotate bugreport:include[x] ::\n+sendemail.bcc bugreport:include[x] ::\n+sendemail.cc bugreport:include[x] ::\n+sendemail.ccCmd bugreport:include[x] ::\n+sendemail.chainReplyTo bugreport:include[x] ::\n+sendemail.confirm bugreport:include[x] ::\n+sendemail.envelopeSender bugreport:include[x] ::\n+sendemail.from bugreport:include[x] ::\n+sendemail.multiEdit bugreport:include[x] ::\n+sendemail.signedoffbycc bugreport:include[x] ::\n+sendemail.smtpPass bugreport:exclude[x] ::\n+sendemail.suppresscc bugreport:include[x] ::\n+sendemail.suppressFrom bugreport:include[x] ::\n+sendemail.to bugreport:include[x] ::\n+sendemail.tocmd bugreport:include[x] ::\n+sendemail.smtpDomain bugreport:include[x] ::\n+sendemail.smtpServer bugreport:include[x] ::\n+sendemail.smtpServerPort bugreport:include[x] ::\n+sendemail.smtpServerOption bugreport:include[x] ::\n+sendemail.smtpUser bugreport:exclude[x] ::\n+sendemail.thread bugreport:include[x] ::\n+sendemail.transferEncoding bugreport:include[x] ::\n+sendemail.validate bugreport:include[x] ::\n+sendemail.xmailer bugreport:include[x] ::\n \tSee linkgit:git-send-email[1] for description.\n \n-sendemail.signedoffcc (deprecated)::\n+sendemail.signedoffcc (deprecated) bugreport:exclude[x] ::\n \tDeprecated alias for `sendemail.signedoffbycc`.\n \n-sendemail.smtpBatchSize::\n+sendemail.smtpBatchSize bugreport:include[x] ::\n \tNumber of messages to be sent per connection, after that a relogin\n \twill happen.  If the value is 0 or undefined, send all messages in\n \tone connection.\n \tSee also the `--batch-size` option of linkgit:git-send-email[1].\n \n-sendemail.smtpReloginDelay::\n+sendemail.smtpReloginDelay bugreport:include[x] ::\n \tSeconds wait before reconnecting to smtp server.\n \tSee also the `--relogin-delay` option of linkgit:git-send-email[1].\ndiff --git a/Makefile b/Makefile\nindex a01a050aa3..2bc9f112ea 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n \n GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n+GENERATED_H += bugreport-config-safelist.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n \t$(FIND) . \\\n@@ -2163,6 +2164,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\tcommand-list.txt >$@+ && mv $@+ $@\n \n+bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n+\n+bugreport-config-safelist.h: Documentation/config/*.txt\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\ndiff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\nnew file mode 100755\nindex 0000000000..44612d5538\n--- /dev/null\n+++ b/generate-bugreport-config-safelist.sh\n@@ -0,0 +1,17 @@\n+#!/bin/sh\n+\n+cat <<EOF\n+/* Automatically generated by bugreport-generate-config-safelist.sh */\n+\n+\n+static const char *bugreport_config_safelist[] = {\n+EOF\n+\n+# cat all regular files in Documentation/config\n+find Documentation/config -type f -exec cat {} \\; |\n+# print the command name which matches the bugreport-include macro\n+sed -n 's/^\\(.*\\) \\+bugreport:include.* ::$/  \"\\1\",/p' | sort\n+\n+cat <<EOF\n+};\n+EOF\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390337","messageId":"20200124033436.81097-11-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 10/15] bugreport: add config values from safelist","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:31Z","receivedAt":"2020-01-24T03:35:37Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nTeach bugreport to gather the values of config options which are present\nin 'bugreport-config-safelist.h'.\n\nMany config options are sensitive, and many Git add-ons use config\noptions which git-core does not know about; it is better only to gather\nconfig options which we know to be safe, rather than excluding options\nwhich we know to be unsafe.\n\nTaking the build-time generated array and putting it into a set saves us\ntime - since git_config_bugreport() is called for every option the user\nhas configured, performing option lookup in constant time is a useful\noptimization.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Makefile    |  2 +-\n bugreport.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 76 insertions(+), 1 deletion(-)\n\ndiff --git a/Makefile b/Makefile\nindex 2bc9f112ea..eb17ece120 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2465,7 +2465,7 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n-git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+git-bugreport$X: bugreport-config-safelist.h bugreport.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(LIBS)\n \ndiff --git a/bugreport.c b/bugreport.c\nindex 07b84b9c94..7a9fd36b60 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -6,6 +6,9 @@\n #include \"help.h\"\n #include \"compat/compiler.h\"\n #include \"run-command.h\"\n+#include \"config.h\"\n+#include \"bugreport-config-safelist.h\"\n+#include \"khash.h\"\n \n static void get_curl_version_info(struct strbuf *curl_info)\n {\n@@ -18,6 +21,40 @@ static void get_curl_version_info(struct strbuf *curl_info)\n \t    strbuf_addstr(curl_info, \"'git-remote-https --build-info' not supported\\n\");\n }\n \n+KHASH_INIT(cfg_set, const char*, int, 0, kh_str_hash_func, kh_str_hash_equal);\n+\n+struct cfgset {\n+\tkh_cfg_set_t set;\n+};\n+\n+struct cfgset safelist;\n+\n+static void cfgset_init(struct cfgset *set, size_t initial_size)\n+{\n+\tmemset(&set->set, 0, sizeof(set->set));\n+\tif (initial_size)\n+\t\tkh_resize_cfg_set(&set->set, initial_size);\n+}\n+\n+static int cfgset_insert(struct cfgset *set, const char *cfg_key)\n+{\n+\tint added;\n+\tkh_put_cfg_set(&set->set, cfg_key, &added);\n+\treturn !added;\n+}\n+\n+static int cfgset_contains(struct cfgset *set, const char *cfg_key)\n+{\n+\tkhiter_t pos = kh_get_cfg_set(&set->set, cfg_key);\n+\treturn pos != kh_end(&set->set);\n+}\n+\n+static void cfgset_clear(struct cfgset *set)\n+{\n+\tkh_release_cfg_set(&set->set);\n+\tcfgset_init(set, 0);\n+}\n+\n static void get_system_info(struct strbuf *sys_info)\n {\n \tstruct strbuf version_info = STRBUF_INIT;\n@@ -54,6 +91,36 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_complete_line(sys_info);\n }\n \n+static void gather_safelist(void)\n+{\n+\tint index;\n+\tint safelist_len = sizeof(bugreport_config_safelist) / sizeof(const char *);\n+\tcfgset_init(&safelist, safelist_len);\n+\tfor (index = 0; index < safelist_len; index++)\n+\t\tcfgset_insert(&safelist, bugreport_config_safelist[index]);\n+\n+}\n+\n+static int git_config_bugreport(const char *var, const char *value, void *cb)\n+{\n+\tstruct strbuf *config_info = (struct strbuf *)cb;\n+\n+\tif (cfgset_contains(&safelist, var))\n+\t\tstrbuf_addf(config_info,\n+\t\t\t    \"%s (%s) : %s\\n\",\n+\t\t\t    var, config_scope_to_string(current_config_scope()),\n+\t\t\t    value);\n+\n+\treturn 0;\n+}\n+\n+static void get_safelisted_config(struct strbuf *config_info)\n+{\n+\tgather_safelist();\n+\tgit_config(git_config_bugreport, config_info);\n+\tcfgset_clear(&safelist);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -94,12 +161,17 @@ int cmd_main(int argc, const char **argv)\n \tFILE *report;\n \ttime_t now = time(NULL);\n \tchar *option_output = NULL;\n+\tint nongit_ok = 0;\n \n \tconst struct option bugreport_options[] = {\n \t\tOPT_STRING('o', \"output\", &option_output, N_(\"path\"),\n \t\t\t   N_(\"specify a destination for the bugreport file\")),\n \t\tOPT_END()\n \t};\n+\n+\t/* Prerequisite for hooks and config checks */\n+\tsetup_git_directory_gently(&nongit_ok);\n+\n \targc = parse_options(argc, argv, \"\", bugreport_options,\n \t\t\t     bugreport_usage, 0);\n \n@@ -118,6 +190,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"System Info\");\n \tget_system_info(&buffer);\n \n+\tget_header(&buffer, \"Safelisted Config Info\");\n+\tget_safelisted_config(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390338","messageId":"20200124033436.81097-12-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 11/15] bugreport: collect list of populated hooks","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:32Z","receivedAt":"2020-01-24T03:35:39Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nOccasionally a failure a user is seeing may be related to a specific\nhook which is being run, perhaps without the user realizing. While the\ncontents of hooks can be sensitive - containing user data or process\ninformation specific to the user's organization - simply knowing that a\nhook is being run at a certain stage can help us to understand whether\nsomething is going wrong.\n\nWithout a definitive list of hook names within the code, we compile our\nown list from the documentation. This is likely prone to bitrot. To\nreduce the amount of code humans need to read, we turn the list into a\nstring_list and iterate over it (as we are calling the same find_hook\noperation on each string). However, since bugreport should primarily be\ncalled by the user, the performance loss from massaging the string\nseems acceptable.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 53 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 7a9fd36b60..4c77009f1b 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -9,6 +9,7 @@\n #include \"config.h\"\n #include \"bugreport-config-safelist.h\"\n #include \"khash.h\"\n+#include \"run-command.h\"\n \n static void get_curl_version_info(struct strbuf *curl_info)\n {\n@@ -121,6 +122,55 @@ static void get_safelisted_config(struct strbuf *config_info)\n \tcfgset_clear(&safelist);\n }\n \n+static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n+{\n+\t/*\n+\t * Doesn't look like there is a list of all possible hooks; so below is\n+\t * a transcription of `git help hook`.\n+\t */\n+\tconst char *hooks = \"applypatch-msg,\"\n+\t\t\t    \"pre-applypatch,\"\n+\t\t\t    \"post-applypatch,\"\n+\t\t\t    \"pre-commit,\"\n+\t\t\t    \"pre-merge-commit,\"\n+\t\t\t    \"prepare-commit-msg,\"\n+\t\t\t    \"commit-msg,\"\n+\t\t\t    \"post-commit,\"\n+\t\t\t    \"pre-rebase,\"\n+\t\t\t    \"post-checkout,\"\n+\t\t\t    \"post-merge,\"\n+\t\t\t    \"pre-push,\"\n+\t\t\t    \"pre-receive,\"\n+\t\t\t    \"update,\"\n+\t\t\t    \"post-receive,\"\n+\t\t\t    \"post-update,\"\n+\t\t\t    \"push-to-checkout,\"\n+\t\t\t    \"pre-auto-gc,\"\n+\t\t\t    \"post-rewrite,\"\n+\t\t\t    \"sendemail-validate,\"\n+\t\t\t    \"fsmonitor-watchman,\"\n+\t\t\t    \"p4-pre-submit,\"\n+\t\t\t    \"post-index-changex\";\n+\tstruct string_list hooks_list = STRING_LIST_INIT_DUP;\n+\tstruct string_list_item *iter = NULL;\n+\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(hook_info,\n+\t\t\t\"not run from a git repository - no hooks to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstring_list_split(&hooks_list, hooks, ',', -1);\n+\n+\tfor_each_string_list_item(iter, &hooks_list) {\n+\t\tif (find_hook(iter->string)) {\n+\t\t\tstrbuf_addstr(hook_info, iter->string);\n+\t\t\tstrbuf_complete_line(hook_info);\n+\t\t}\n+\t}\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -193,6 +243,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Safelisted Config Info\");\n \tget_safelisted_config(&buffer);\n \n+\tget_header(&buffer, \"Configured Hooks\");\n+\tget_populated_hooks(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390339","messageId":"20200124033436.81097-14-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 13/15] bugreport: add packed object summary","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:34Z","receivedAt":"2020-01-24T03:35:43Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nAlongside the loose object counts, it can be useful to show the number\nof packs and packed objects. This way we can check whether the repo has\nan appropriate ratio of packed to loose objects to help determine\nwhether it's behaving correctly.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 38 ++++++++++++++++++++++++++++++++++++++\n 1 file changed, 38 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex bf10857183..45cc1764e0 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -214,6 +214,41 @@ static void get_loose_object_summary(struct strbuf *obj_info) {\n \t\t    total_count_questionable ? \" (problem during count)\" : \"\");\n }\n \n+struct packed_object_cb_data {\n+\tstruct packed_git *last_pack;\n+\tint pack_count;\n+\tint object_count;\n+};\n+\n+static int packed_object_cb(const struct object_id *oid,\n+\t\t\t    struct packed_git *pack,\n+\t\t\t    uint32_t pos,\n+\t\t\t    void *data) {\n+\tstruct packed_object_cb_data *cb_data = data;\n+\n+\tif (!cb_data)\n+\t\treturn 1;\n+\n+\tif (pack && pack != cb_data->last_pack) {\n+\t\tcb_data->last_pack = pack;\n+\t\tcb_data->pack_count++;\n+\t}\n+\n+\tcb_data->object_count++;\n+\n+\treturn 0;\n+}\n+\n+static void get_packed_object_summary(struct strbuf *obj_info)\n+{\n+\tstruct packed_object_cb_data cb_data = {NULL, 0, 0};\n+\n+\tfor_each_packed_object(packed_object_cb, &cb_data, 0);\n+\n+\tstrbuf_addf(obj_info, \"%d total packs (%d objects)\\n\",\n+\t\t    cb_data.pack_count, cb_data.object_count);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -292,6 +327,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Loose Object Counts\");\n \tget_loose_object_summary(&buffer);\n \n+\tget_header(&buffer, \"Packed Object Summary\");\n+\tget_packed_object_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390340","messageId":"20200124033436.81097-13-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 12/15] bugreport: count loose objects","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:33Z","receivedAt":"2020-01-24T03:35:43Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nThe number of unpacked objects in a user's repository may help us\nunderstand the root of the problem they're seeing, especially if a\ncommand is running unusually slowly.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\nThe refactor removed much of the code Dscho suggested; and yet it\nremains true that he helped me while developing this commit (although\nhis suggestions didn't survive). Shall I leave the Helped-by line or\nremove it?\n\n - Emily\n\n\n bugreport.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 46 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 4c77009f1b..bf10857183 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -10,6 +10,7 @@\n #include \"bugreport-config-safelist.h\"\n #include \"khash.h\"\n #include \"run-command.h\"\n+#include \"object-store.h\"\n \n static void get_curl_version_info(struct strbuf *curl_info)\n {\n@@ -171,6 +172,48 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n \t}\n }\n \n+static int loose_object_cb(const struct object_id *oid, const char *path,\n+\t\t\t   void *data) {\n+\tint *loose_object_count = data;\n+\n+\tif (loose_object_count) {\n+\t\t(*loose_object_count)++;\n+\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static void get_loose_object_summary(struct strbuf *obj_info) {\n+\n+\tint local_loose_object_count = 0, total_loose_object_count = 0;\n+\tint local_count_questionable = 0, total_count_questionable = 0;\n+\n+\tlocal_count_questionable = for_each_loose_object(\n+\t\t\t\t\tloose_object_cb,\n+\t\t\t\t\t&local_loose_object_count,\n+\t\t\t\t\tFOR_EACH_OBJECT_LOCAL_ONLY);\n+\n+\ttotal_count_questionable = for_each_loose_object(\n+\t\t\t\t\tloose_object_cb,\n+\t\t\t\t\t&total_loose_object_count,\n+\t\t\t\t\t0);\n+\n+\tstrbuf_addf(obj_info, \"%d local loose objects%s\\n\",\n+\t\t    local_loose_object_count,\n+\t\t    local_count_questionable ? \" (problem during count)\" : \"\");\n+\n+\tstrbuf_addf(obj_info, \"%d alternate loose objects%s\\n\",\n+\t\t    total_loose_object_count - local_loose_object_count,\n+\t\t    (local_count_questionable || total_count_questionable)\n+\t\t\t? \" (problem during count)\"\n+\t\t\t: \"\");\n+\n+\tstrbuf_addf(obj_info, \"%d total loose objects%s\\n\",\n+\t\t    total_loose_object_count,\n+\t\t    total_count_questionable ? \" (problem during count)\" : \"\");\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -246,6 +289,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Configured Hooks\");\n \tget_populated_hooks(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Loose Object Counts\");\n+\tget_loose_object_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390341","messageId":"20200124033436.81097-15-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 14/15] bugreport: list contents of $OBJDIR/info","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:35Z","receivedAt":"2020-01-24T03:35:46Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nMiscellaneous information used about the object store can end up in\n.git/objects/info; this can help us understand what may be going on with\nthe object store when the user is reporting a bug. Otherwise, it could\nbe difficult to track down what is going wrong with an object which\nisn't kept locally to .git/objects/ or .git/objects/pack. Having some\nunderstanding of where the user's objects may be kept can save us some\nhops during the bug reporting process.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 48 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 45cc1764e0..12463ffdc7 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -249,6 +249,51 @@ static void get_packed_object_summary(struct strbuf *obj_info)\n \t\t    cb_data.pack_count, cb_data.object_count);\n }\n \n+static void list_contents_of_dir_recursively(struct strbuf *contents,\n+\t\t\t\t      \t     struct strbuf *dirpath)\n+{\n+\tstruct dirent *d;\n+\tDIR *dir;\n+\tsize_t path_len;\n+\n+\tdir = opendir(dirpath->buf);\n+\tif (!dir)\n+\t\treturn;\n+\n+\tstrbuf_complete(dirpath, '/');\n+\tpath_len = dirpath->len;\n+\n+\twhile ((d = readdir(dir))) {\n+\t\tif (!strcmp(d->d_name, \".\") || !strcmp(d->d_name, \"..\"))\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_addbuf(contents, dirpath);\n+\t\tstrbuf_addstr(contents, d->d_name);\n+\t\tstrbuf_complete_line(contents);\n+\n+\t\tif (d->d_type == DT_DIR) {\n+\t\t\tstrbuf_addstr(dirpath, d->d_name);\n+\t\t\tlist_contents_of_dir_recursively(contents, dirpath);\n+\t\t}\n+\t\tstrbuf_setlen(dirpath, path_len);\n+\t}\n+\n+\tclosedir(dir);\n+}\n+\n+static void get_object_info_summary(struct strbuf *obj_info)\n+{\n+\tstruct strbuf dirpath = STRBUF_INIT;\n+\n+\tstrbuf_addstr(&dirpath, get_object_directory());\n+\tstrbuf_complete(&dirpath, '/');\n+\tstrbuf_addstr(&dirpath, \"info/\");\n+\n+\tlist_contents_of_dir_recursively(obj_info, &dirpath);\n+\n+\tstrbuf_release(&dirpath);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -330,6 +375,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Packed Object Summary\");\n \tget_packed_object_summary(&buffer);\n \n+\tget_header(&buffer, \"Object Info Summary\");\n+\tget_object_info_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390342","messageId":"20200124033436.81097-16-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v5 15/15] bugreport: summarize contents of alternates file","fromName":"","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:34:36Z","receivedAt":"2020-01-24T03:35:49Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nIn some cases, it could be that the user is having a problem with an\nobject which isn't present in their normal object directory. We can get\na hint that that might be the case by examining the list of alternates\nwhere their object may be stored instead. Since paths to alternates may\nbe sensitive, we'll instead count how many alternates have been\nspecified and note how many of them exist or are broken.\n\nWhile object-cache.h describes a function \"foreach_alt_odb()\", this\nfunction does not provide information on broken alternates, which are\nskipped over in \"link_alt_odb_entry()\". Since the goal is to identify\nmissing alternates, we can gather the contents of\n.git/objects/info/alternates manually.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n bugreport.c | 39 +++++++++++++++++++++++++++++++++++++++\n 1 file changed, 39 insertions(+)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 12463ffdc7..2c540182dd 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -294,6 +294,42 @@ static void get_object_info_summary(struct strbuf *obj_info)\n \tstrbuf_release(&dirpath);\n }\n \n+static void get_alternates_summary(struct strbuf *alternates_info)\n+{\n+\tstruct strbuf alternates_path = STRBUF_INIT;\n+\tstruct strbuf alternate = STRBUF_INIT;\n+\tFILE *file;\n+\tsize_t exists = 0, broken = 0;\n+\n+\tstrbuf_addstr(&alternates_path, get_object_directory());\n+\tstrbuf_complete(&alternates_path, '/');\n+\tstrbuf_addstr(&alternates_path, \"info/alternates\");\n+\n+\tfile = fopen(alternates_path.buf, \"r\");\n+\tif (!file) {\n+\t\tstrbuf_addstr(alternates_info, \"No alternates file found.\\n\");\n+\t\tstrbuf_release(&alternates_path);\n+\t\treturn;\n+\t}\n+\n+\twhile (strbuf_getline(&alternate, file) != EOF) {\n+\t\tif (!access(alternate.buf, F_OK))\n+\t\t\texists++;\n+\t\telse\n+\t\t\tbroken++;\n+\t}\n+\n+\tstrbuf_addf(alternates_info,\n+\t\t    \"%zd alternates found (%zd working, %zd broken)\\n\",\n+\t\t    exists + broken,\n+\t\t    exists,\n+\t\t    broken);\n+\n+\tfclose(file);\n+\tstrbuf_release(&alternate);\n+\tstrbuf_release(&alternates_path);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output <file>]\"),\n \tNULL\n@@ -378,6 +414,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Object Info Summary\");\n \tget_object_info_summary(&buffer);\n \n+\tget_header(&buffer, \"Alternates\");\n+\tget_alternates_summary(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \tstrbuf_write(&buffer, report);\n \tfclose(report);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"390343","messageId":"20200124033841.GB37541@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"Re: [PATCH v5 00/15] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-24T03:38:41Z","receivedAt":"2020-01-24T03:38:49Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"A sample bugreport generated from this patchset follows:\n\nThank you for filling out a Git bug report!\nPlease answer the following questions to help us understand your issue.\n\nWhat did you do before the bug happened? (Steps to reproduce your issue)\n\nWhat did you expect to happen? (Expected behavior)\n\nWhat happened instead? (Actual behavior)\n\nWhat's different between what you expected and what actually happened?\n\nAnything else you want to add:\n\nPlease review the rest of the bug report below.\nYou can delete any lines you don't wish to send.\n\n\n[System Info]\ngit version:\ngit version 2.25.0.18.g682ab0d3eb\ncpu: x86_64\nbuilt from commit: 682ab0d3eb8b84f8af4db1a161d24ca53d2f39fc\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nuname -a: Linux 5.2.17-1rodete3-amd64 #1 SMP Debian 5.2.17-1rodete3 (2019-10-21 > 2018) x86_64\ncompiler info: glibc: 2.28\n$SHELL (typically, interactive shell): /bin/bash\ngit-remote-https --build-info:\ngit-http-fetch version: 2.25.0.18.g682ab0d3eb\nbuilt from commit: 682ab0d3eb8b84f8af4db1a161d24ca53d2f39fc\ncurl version: libcurl/7.66.0 GnuTLS/3.6.9 zlib/1.2.11 brotli/1.0.7 libidn2/2.2.0 libpsl/0.20.2 (+libidn2/2.2.0) libssh2/1.8.0 nghttp2/1.39.2 librtmp/2.3\n\n\n[Safelisted Config Info]\nsendemail.from (global) : emilyshaffer@google.com\nsendemail.from (repo) : emilyshaffer@google.com\n\n\n[Configured Hooks]\npre-commit\nprepare-commit-msg\n\n\n[Loose Object Counts]\n2549 local loose objects\n2641 alternate loose objects\n5190 total loose objects\n\n\n[Packed Object Summary]\n60 total packs (591308 objects)\n\n\n[Object Info Summary]\n.git/objects/info/foo\n.git/objects/info/bar\n.git/objects/info/bar/baz\n.git/objects/info/alternates\n\n\n[Alternates]\n2 alternates found (1 working, 1 broken)\n"},{"id":"390675","messageId":"20200128230421.49994-1-jonathantanmy@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"Re: [PATCH v5 00/15] add git-bugreport tool","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2020-01-28T23:04:21Z","receivedAt":"2020-01-28T23:04:54Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"> From: Emily Shaffer <emilyshaffer@google.com>\n> \n> This topic branch depends on the patch mailed in\n> lore.kernel.org/git/20191211233820.185153-1-emilyshaffer@google.com in order to\n> display scopes for configs gathered during \"bugreport: add config values from\n> safelist\".\n> \n> I'll summarize v4-v5. Since v4 has languished for some time, I don't\n> think an interdiff is too helpful, so I won't include one. Bonus, the\n> code is much simplified from some suggestions from Junio on how to\n> inspect objects, so I hope it's easy to review anyways.\n\nTo everyone in the developer community interested in this set: what is\nthe status of this?\n\nIf this needs further review, then maybe it would be best if only\npatches 1-4 were put up for submission first, with a note in the\nbugreport documentation that more information may be added in future Git\nversions. For me, patches 1-4 look good and I don't have enough\nexperience with uname (especially across libcs and OSes) to determine\nwhat should or should not be included - if this is typical of reviewers\nin the Git project, it might be better to submit patches 1-4 first, and\nthen send each additional diagnostic separately, so that people who know\nwhat's going on in one area but not another can just comment on the area\nthey know about.\n\nHaving said that, I see that a few people have already looked at the\nentire patchset and made comments, so if they are OK with it, we don't\nneed to split it up.\n"},{"id":"390677","messageId":"20200128232608.GA182648@google.com","threadId":"52442","inReplyTo":"20200128230421.49994-1-jonathantanmy@google.com","subject":"Re: [PATCH v5 00/15] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-01-28T23:26:08Z","receivedAt":"2020-01-28T23:26:16Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Jan 28, 2020 at 03:04:21PM -0800, Jonathan Tan wrote:\n> > From: Emily Shaffer <emilyshaffer@google.com>\n> > \n> > This topic branch depends on the patch mailed in\n> > lore.kernel.org/git/20191211233820.185153-1-emilyshaffer@google.com in order to\n> > display scopes for configs gathered during \"bugreport: add config values from\n> > safelist\".\n> > \n> > I'll summarize v4-v5. Since v4 has languished for some time, I don't\n> > think an interdiff is too helpful, so I won't include one. Bonus, the\n> > code is much simplified from some suggestions from Junio on how to\n> > inspect objects, so I hope it's easy to review anyways.\n> \n> To everyone in the developer community interested in this set: what is\n> the status of this?\n> \n> If this needs further review, then maybe it would be best if only\n> patches 1-4 were put up for submission first, with a note in the\n> bugreport documentation that more information may be added in future Git\n> versions. For me, patches 1-4 look good and I don't have enough\n> experience with uname (especially across libcs and OSes) to determine\n> what should or should not be included - if this is typical of reviewers\n> in the Git project, it might be better to submit patches 1-4 first, and\n> then send each additional diagnostic separately, so that people who know\n> what's going on in one area but not another can just comment on the area\n> they know about.\n> \n> Having said that, I see that a few people have already looked at the\n> entire patchset and made comments, so if they are OK with it, we don't\n> need to split it up.\n\nI'd be fine with either; from now, my gut says the only ones I'm not\ncomfortable merging today are maybe 10, as Junio had some concerns about\nwhether to allow glob expansion, and 11, as it's prone to rot and I'm\ndoing other work in that area which would cause 11 to be\ndropped/refactored anyways once it goes in. Otherwise I think they're\nall pretty OK to go in and let the other work continue later in a\ndifferent thread.\n\nOf course, as an author my opinion that they're good to go doesn't mean\nmuch ;)\n\n - Emily\n"},{"id":"390851","messageId":"CAN0heSrwxnHGR0JP9EHgAHYysFO+E2qqV2JGO2qLaMM=MrA=LQ@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"Re: [PATCH v5 00/15] add git-bugreport tool","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:15:25Z","receivedAt":"2020-01-30T22:15:40Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:35, <emilyshaffer@google.com> wrote:\n> This topic branch depends on the patch mailed in\n> lore.kernel.org/git/20191211233820.185153-1-emilyshaffer@google.com in order to\n> display scopes for configs gathered during \"bugreport: add config values from\n> safelist\".\n\nShould this use `config_scope_name()` which looks like it's about\nto graduate [1]? Disclaimer: I haven't followed that patch set too closely.\n\n[1] https://lore.kernel.org/git/xmqqzhe66dav.fsf@gitster-ct.c.googlers.com/\n\n\n\nMartin\n"},{"id":"390852","messageId":"CAN0heSoaASfMhgLwZx4MZAdoGOfGK1fJK5X9VfUJN5R38gFVTA@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-2-emilyshaffer@google.com","subject":"Re: [PATCH v5 01/15] bugreport: add tool to generate debugging info","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:18:55Z","receivedAt":"2020-01-30T22:19:08Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 05:56, <emilyshaffer@google.com> wrote:\n>\n> From: Emily Shaffer <emilyshaffer@google.com>\n>\n> Teach Git how to prompt the user for a good bug report: reproduction\n> steps, expected behavior, and actual behavior. Later, Git can learn how\n> to collect some diagnostic information from the repository.\n\n(\"Later\" meaning \"later in this series\", or \"any day now\"? ;-) )\n\n> +SYNOPSIS\n> +--------\n> +[verse]\n> +'git bugreport' [-o | --output <path>]\n\nHmm. Should that be \"[(-o | --output) <path>]\"?\n\n> +DESCRIPTION\n> +-----------\n> +Captures information about the user's machine, Git client, and repository state,\n> +as well as a form requesting information about the behavior the user observed,\n> +into a single text file which the user can then share, for example to the Git\n> +mailing list, in order to report an observed bug.\n\nNice description. Got it.\n\n> +The following information is requested from the user:\n> +\n> + - Reproduction steps\n> + - Expected behavior\n> + - Actual behavior\n> +\n> +The following information is captured automatically:\n> +\n> + - Git version (`git version --build-options`)\n> + - Machine information (`uname -a`)\n> + - Versions of various dependencies\n> + - Git config contents (`git config --show-origin --list`)\n> + - The names of all configured git-hooks in `.git/hooks/`\n\nI would have expected these points to appear later, both to make it\nclear what this does commit does (and not), and to highlight what\nuser-visible (documentation-worthy) changes later commits bring along.\n\n> +OPTIONS\n> +-------\n> +-o [<path>]::\n> +--output [<path>]::\n\nDrop the \"[\" and \"]\"? If you give -o, you'd better give a path as well?\n\n> +       Place the resulting bug report file in <path> instead of the root of the\n\n`<path>`\n\n> +\"Please review the rest of the bug report below.\\n\"\n> +\"You can delete any lines you don't wish to send.\\n\");\n\n\"send\" sounds like we're *just* about to send this report somewhere, but\nit's \"only\" going to be written to the disk. Maybe \"share\", instead?\n\n> +       if (option_output) {\n> +               strbuf_addstr(&report_path, option_output);\n> +               strbuf_complete(&report_path, '/');\n> +       }\n\nI thought I'd use `-o` to indicate the filename, but it turns out it's\nthe *directory* where the file (of some semi-random, generated name)\nwill end up. Re-reading the docs further up, I can see how this is\nconsistent. I sort of wonder if this should be `--output*-directory*`\nfor symmetry with `git format-patch`.\n\n> +       strbuf_addstr(&report_path, \"git-bugreport-\");\n> +       strbuf_addftime(&report_path, \"%F\", gmtime(&now), 0, 0);\n> +       strbuf_addstr(&report_path, \".txt\");\n> +\n> +\n\n(Double blank line?)\n\n> +       get_bug_template(&buffer);\n> +\n> +       report = fopen_for_writing(report_path.buf);\n\nReport might be NULL here.\n\nIf there's already such a file, we overwrite. Should we generate the\nfilename using not just today's date (two bug reports in a day wouldn't\nbe unheard of?) but also something like hh:mm:ss?\n\n> +       strbuf_write(&buffer, report);\n> +       fclose(report);\n\nMaybe clear the strbuf around here...\n\n> +       launch_editor(report_path.buf, NULL, NULL);\n> +       return 0;\n\n... and/or UNLEAK it here, together with report_path.\n\nMaybe \"return -launch_editor(...)\"?\n\n> +#!/bin/bash\n\nUse /bin/sh instead?\n\n> +# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n> +# information there; we can make sure all our headers were followed by some\n> +# information to check if the command was successful.\n> +HEADER_PATTERN=\"^\\[.*\\]$\"\n> +check_all_headers_populated() {\n> +       while read -r line; do\n> +               if [$(grep $HEADER_PATTERN $line)]; then\n\nI think this is a bash-ism.\n\n> +                       read -r nextline\n> +                       if [-z $nextline]; then\n\nLikewise.\n\n> +                               return 1;\n> +                       fi\n> +               fi\n> +       done\n> +}\n> +\n> +test_expect_success 'creates a report with content in the right places' '\n> +       git bugreport &&\n> +       check_all_headers_populated <git-bugreport-* &&\n> +       rm git-bugreport-*\n> +'\n> +\n> +test_expect_success '--output puts the report in the provided dir' '\n> +       mkdir foo/ &&\n\nIf foo isn't there, do we not create it? Apparently not -- in my\ntesting, we segfault. (We don't check for NULL after opening the file.)\n\n> +       git bugreport -o foo/ &&\n> +       test -f foo/git-bugreport-* &&\n\ntest_path_is_file\n\n> +       rm -fr foo/\n> +'\n> +\n> +test_expect_success 'incorrect arguments abort with usage' '\n> +       test_must_fail git bugreport --false 2>output &&\n> +       grep usage output &&\n> +       test ! -f git-bugreport-*\n\ntest_path_is_missing\n\n\nMartin\n"},{"id":"390853","messageId":"CAN0heSo6K42mmPkLE=QPo93OJmzbN0Xj-uYOE-wOT2N5ctda5g@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-3-emilyshaffer@google.com","subject":"Re: [PATCH v5 02/15] help: move list_config_help to builtin/help","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:19:26Z","receivedAt":"2020-01-30T22:19:40Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> To make help.o usable by other commands again, move list_config_help()\n> into builtin/help.c (where it makes sense to assume other builtin libraries\n> are present).\n\nNit: I think this could be patch 01/15. It shuffles things around --\n*then*, starting with patch 02/15, we can add exciting stuff.\n\n\nMartin\n"},{"id":"390854","messageId":"CAN0heSqaeaBTCmiY=f0eD8=hsPV7BL9OCFL=Oq7je+t_o4frqA@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-4-emilyshaffer@google.com","subject":"Re: [PATCH v5 03/15] bugreport: gather git version and build info","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:19:55Z","receivedAt":"2020-01-30T22:20:11Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> +static void get_system_info(struct strbuf *sys_info)\n> +{\n> +       struct strbuf version_info = STRBUF_INIT;\n> +\n> +       /* get git version from native cmd */\n> +       strbuf_addstr(sys_info, \"git version:\\n\");\n> +       get_version_info(&version_info, 1);\n> +       strbuf_addbuf(sys_info, &version_info);\n> +       strbuf_complete_line(sys_info);\n\nThis leaks version_info.\n\n> +}\n\n\nMartin\n"},{"id":"390855","messageId":"CAN0heSqKXAxOGBayEx+29EKFKqBWhrCymUF5X++OVj78=zhdmw@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-5-emilyshaffer@google.com","subject":"Re: [PATCH v5 04/15] help: add shell-path to --build-options","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:21:05Z","receivedAt":"2020-01-30T22:21:18Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> It may be useful to know which shell Git was built to try to point to,\n> in the event that shell-based Git commands are failing. $SHELL_PATH is\n> set during the build and used to launch the manpage viewer, as well as\n> by git-compat-util.h, and it's used during tests. 'git version\n> --build-options' is encouraged for use in bug reports, so it makes sense\n> to include this information there.\n\nHmm, similar nit as for patch 02/15: This could go in as, e.g., 02/15 and\nyour 01/15 would be 03/15: This patch would be useful even without `git\nbugreport`.\n\n\nMartin\n"},{"id":"390856","messageId":"CAN0heSoh87_16y+B5=UXAhbaVnejmRj3XXjy5viABheBz+D3fA@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-7-emilyshaffer@google.com","subject":"Re: [PATCH v5 06/15] bugreport: add compiler info","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:21:39Z","receivedAt":"2020-01-30T22:21:52Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> +#else\n> +\n> +static inline void get_compiler_info(struct strbuf *info)\n> +{\n> +       strbuf_addstr(info, \"get_compiler_info() not implemented\");\n\nMaybe \"no compiler info available\" (or s/ available//, or\ns/available/reported/), or something else more human-readable?\n\n\n> +}\n> +\n> +#endif\n> +\n> +#endif /* COMPILER_H */\n\nMartin\n"},{"id":"390857","messageId":"CAN0heSqiMvMopqpMrnOffsO-nZ6UPWbuHQdB9VxLhWhm-d95rA@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-8-emilyshaffer@google.com","subject":"Re: [PATCH v5 07/15] bugreport: add curl version","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:27:45Z","receivedAt":"2020-01-30T22:27:58Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:41, <emilyshaffer@google.com> wrote:\n> +static void get_curl_version_info(struct strbuf *curl_info)\n> +{\n> +       struct child_process cp = CHILD_PROCESS_INIT;\n> +\n> +       argv_array_push(&cp.args, \"git\");\n> +       argv_array_push(&cp.args, \"remote-https\");\n> +       argv_array_push(&cp.args, \"--build-info\");\n> +       if (capture_command(&cp, curl_info, 0))\n> +           strbuf_addstr(curl_info, \"'git-remote-https --build-info' not supported\\n\");\n> +}\n>\n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n> @@ -31,6 +43,10 @@ static void get_system_info(struct strbuf *sys_info)\n>         strbuf_addstr(sys_info, \"compiler info: \");\n>         get_compiler_info(sys_info);\n>         strbuf_complete_line(sys_info);\n> +\n> +       strbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n> +       get_curl_version_info(sys_info);\n\nThe header here looks a lot like an implementation detail of\n`get_curl_version_info()`. Or put differently, these risk getting out of\nsync. Maybe frame the header a bit more human readable: \"curl version\".\nBut is this \"curl version\", or more like \"git-remote-https version\"?\nThere's some discrepancy here.\n\n> +       strbuf_complete_line(sys_info);\n>  }\n\n\nMartin\n"},{"id":"390858","messageId":"CAN0heSq9AdF_WPmSkxDA3cPzOQBAbuw4oa+8azvLtjbP-jQfKw@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-9-emilyshaffer@google.com","subject":"Re: [PATCH v5 08/15] bugreport: include user interactive shell","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:28:40Z","receivedAt":"2020-01-30T22:28:53Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:41, <emilyshaffer@google.com> wrote:\n> +       char *shell = NULL;\n\n(Unnecessary initialization.)\n\n> +       shell = getenv(\"SHELL\");\n> +       strbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n> +                   shell ? shell : \"(NULL)\");\n\nThanks for avoiding a classic pitfall. :-)\n\n\"<unused>\" instead of \"(NULL)\"? \"NULL\" is mostly an implementation\ndetail.\n\n\nMartin\n"},{"id":"390860","messageId":"CAN0heSq_i4EitqYH-qrZyXBU+=PUNcSXOOJDHLSnJ1ufV0WtaQ@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-10-emilyshaffer@google.com","subject":"Re: [PATCH v5 09/15] bugreport: generate config safelist based on docs","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:34:24Z","receivedAt":"2020-01-30T22:34:38Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:35, <emilyshaffer@google.com> wrote:\n> Add a new step to the build to generate a safelist of git-config\n> variables which are appropriate to include in the output of\n> git-bugreport. New variables can be added to the safelist by annotating\n> their documentation in Documentation/config with the\n> \"bugreport\" macro, which is recognized by AsciiDoc and\n> AsciiDoctor.\n>\n> Some configs are private in nature, and can contain remote URLs,\n> passwords, or other sensitive information. In the event that a user\n> doesn't notice their information while reviewing a bugreport, that user\n> may leak their credentials to other individuals, mailing lists, or bug\n> tracking tools inadvertently. Heuristic blocklisting of configuration\n> keys is imperfect and prone to false negatives; given the nature of the\n> information which can be leaked, a safelist is more reliable.\n\nI sort of wonder whether safelist/blocklist is to prefer over\nwhitelist/blacklist, or if it's the other way round. The former are new\nto me, whereas the latter are the terms I would have used. But that's\njust me, of course. I was a little surprised, that's all.\n\n> Implement a new no-op \"bugreport\" macro for use as\n> \"bugreport:include[x]\" to annotate the config keys that should be\n> included in the automatically generated safelist. Use \"exclude\" for the\n> others.\n>\n> With Asciidoctor, it's ok to say \"bugreport:include[]\", but AsciiDoc\n> seems to want something between the brackets. A bit unfortunate, but\n> not a huge problem -- we'll just provide an \"x\".\n\nI recognize this reasoning :-) and I'm not terribly opposed to it, but\nafter some nights' sleeping on this, I have to wonder if\n\"annotate:bugreport[include]\" wouldn't be better than \"bugreport[x]\"\nwith that ugly \"x\". Maybe this isn't the biggest problem, but if we\nexpect this macro to eventually sit right next to ~90% of all our config\nvariables...\n\n> \"doc-diff\" reports that this macro doesn't render at all. That is,\n> these are both empty after this commit:\n>\n>   cd Documentation\n>   ./doc-diff --asciidoctor :/\"bugreport: add tool\" HEAD\n>   ./doc-diff --asciidoc    :/\"bugreport: add tool\" HEAD\n\nThat was true in [1], but alas, no more. In that patch, it's sort of\nobvious from the diff how it adds a \"class\" which \"end\"s.\n\n[1] https://lore.kernel.org/git/20190817203846.31609-1-martin.agren@gmail.com/\n\n> --- a/Documentation/asciidoctor-extensions.rb\n> +++ b/Documentation/asciidoctor-extensions.rb\n> @@ -37,6 +37,10 @@ module Git\n>            output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n>          end\n>          output\n> +\n> +    class BugReportProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n> +      def process(parent, action, attrs)\n> +        \"\"\n>        end\n>      end\n>    end\n\nBut this one doesn't add an \"end\", and Asciidoctor trips up badly.\n\n> +  # The bugreport macro does nothing as far as rendering is\n> +  # concerned -- we just grep for it in the sources.\n> +  inline_macro Git::Documentation::BugReportProcessor, :bugreport\n\n(I never much liked this copy-paste comment then, and I still don't, to\nbe honest.)\n\n\n\nMartin\n"},{"id":"390861","messageId":"CAN0heSr3WTtGh=gWTiXYEoSGGHPF_YniA9xH989=OtYfM2-Evw@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-11-emilyshaffer@google.com","subject":"Re: [PATCH v5 10/15] bugreport: add config values from safelist","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-30T22:36:43Z","receivedAt":"2020-01-30T22:36:56Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -2465,7 +2465,7 @@ endif\n>  git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n>         $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n>\n> -git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n> +git-bugreport$X: bugreport-config-safelist.h bugreport.o GIT-LDFLAGS $(GITLIBS)\n>         $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n>                 $(LIBS)\n\nHaven't looked at this patch at all, except I've noticed that something\nis up with the dependencies. I think bugreport.o needs to depend on\nbugreport-config-safelist.h. As it is, the latter may or may not be\navailable as bugreport.o is built. (Reproduces fairly well for me with\nsomething like `make clean && make -j16`.)\n\nI'll try to continue tomorrow. :-)\n\n\nMartin\n"},{"id":"390964","messageId":"CAN0heSo2ujJr_Mi5xPv86NneLoXT3DM3dnRmTACs2VQERBq76Q@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-10-emilyshaffer@google.com","subject":"Re: [PATCH v5 09/15] bugreport: generate config safelist based on docs","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-31T21:20:05Z","receivedAt":"2020-01-31T21:20:19Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:35, <emilyshaffer@google.com> wrote:\n> Add a new step to the build to generate a safelist of git-config\n> variables which are appropriate to include in the output of\n> git-bugreport. New variables can be added to the safelist by annotating\n> their documentation in Documentation/config with the\n> \"bugreport\" macro, which is recognized by AsciiDoc and\n> AsciiDoctor.\n\n\"which is recognized by\" sounds like it's built-in. Maybe \"with a new\nno-op 'bugreport' macro\" or something like that.\n\n> -sendemail.signedoffcc (deprecated)::\n> +sendemail.signedoffcc (deprecated) bugreport:exclude[x] ::\n>         Deprecated alias for `sendemail.signedoffbycc`.\n>\n> -sendemail.smtpBatchSize::\n> +sendemail.smtpBatchSize bugreport:include[x] ::\n>         Number of messages to be sent per connection, after that a relogin\n>         will happen.  If the value is 0 or undefined, send all messages in\n>         one connection.\n>         See also the `--batch-size` option of linkgit:git-send-email[1].\n\nDo we really need to list includes *and* excludes? I could see the point\nof adding an exclude here and there to signal that \"this might look\ninnocent enough, but trust me, we really need to exclude this\" in order\nto avoid future commits to more or less accidentally over-include.\nShould we add some internal documentation and/or a remark in the commit\nmessage about this? As an example, is \"sendemail.signedofcc\" sensitive\nenough that we need to explicitly exclude it? If someone wants to come\nalong and include it, they don't just need to argue for an inclusion,\nbut also for lifting the exclusion. Hmm?\n\nMartin\n"},{"id":"390966","messageId":"CAN0heSo_Ois83gqNrHvNn2HSMMTXvKShxTb_RdG2qY6D7rnthA@mail.gmail.com","threadId":"52442","inReplyTo":"20200124033436.81097-11-emilyshaffer@google.com","subject":"Re: [PATCH v5 10/15] bugreport: add config values from safelist","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-01-31T21:25:06Z","receivedAt":"2020-01-31T21:25:20Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> Taking the build-time generated array and putting it into a set saves us\n> time - since git_config_bugreport() is called for every option the user\n> has configured, performing option lookup in constant time is a useful\n> optimization.\n\nI'm sympathetic to your sending out what you have to obtain comments,\nknowing that it's not perfect. It would have saved me some time and\neffort if I'd known that this was the case though. An \"[RFC]\" tag,\nperhaps. Or at least tweaking the above part of this commit message to\nsay that this might be over-engineered, with a reference to [1].\n\n[1] https://lore.kernel.org/git/20200124032905.GA37541@google.com/\n\n> +       int safelist_len = sizeof(bugreport_config_safelist) / sizeof(const char *);\n\nI was going to suggest ARRAY_SIZE, but then I realized there are some\noutstanding questions around whether you need this stuff in the first\nplace. I'd be inclined to guess that the first version of this would be\n\"for each safelisted item, obtain it and include\", ignoring any \"a.*.b\"\nbusiness. In which case you wouldn't really need this hashset stuff.\n\n\nMartin\n"},{"id":"391066","messageId":"20200204000751.GA87163@google.com","threadId":"52442","inReplyTo":"CAN0heSrwxnHGR0JP9EHgAHYysFO+E2qqV2JGO2qLaMM=MrA=LQ@mail.gmail.com","subject":"Re: [PATCH v5 00/15] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-04T00:07:51Z","receivedAt":"2020-02-04T00:07:58Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:15:25PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:35, <emilyshaffer@google.com> wrote:\n> > This topic branch depends on the patch mailed in\n> > lore.kernel.org/git/20191211233820.185153-1-emilyshaffer@google.com in order to\n> > display scopes for configs gathered during \"bugreport: add config values from\n> > safelist\".\n> \n> Should this use `config_scope_name()` which looks like it's about\n> to graduate [1]? Disclaimer: I haven't followed that patch set too closely.\n\nYeah, you're right that I can use it. config.h:config_scope_name() is a\nnew feature on that patch since last time I looked. Thanks for the tip!\n\n - Emily\n\n> [1] https://lore.kernel.org/git/xmqqzhe66dav.fsf@gitster-ct.c.googlers.com/\n"},{"id":"391067","messageId":"20200204005353.GB87163@google.com","threadId":"52442","inReplyTo":"CAN0heSo6K42mmPkLE=QPo93OJmzbN0Xj-uYOE-wOT2N5ctda5g@mail.gmail.com","subject":"Re: [PATCH v5 02/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-04T00:53:53Z","receivedAt":"2020-02-04T00:54:00Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:19:26PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> > To make help.o usable by other commands again, move list_config_help()\n> > into builtin/help.c (where it makes sense to assume other builtin libraries\n> > are present).\n> \n> Nit: I think this could be patch 01/15. It shuffles things around --\n> *then*, starting with patch 02/15, we can add exciting stuff.\n\nSounds reasonable, here and 04/15. Will do.\n"},{"id":"391088","messageId":"xmqqh8068a5k.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200124033436.81097-12-emilyshaffer@google.com","subject":"Re: [PATCH v5 11/15] bugreport: collect list of populated hooks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-04T18:44:39Z","receivedAt":"2020-02-04T18:44:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"emilyshaffer@google.com writes:\n\n> +\t/*\n> +\t * Doesn't look like there is a list of all possible hooks; so below is\n> +\t * a transcription of `git help hook`.\n\nThat's \"git help hooks\", if I tried my reproduction correctly.  A\nstraight-forward (in the sense of \"what we want in the outcome is\nquite clear\" and not in the sense of \"anybody can design and\nimplement it with a single 30-line patch\") follow-up we can make\nafter this series lands is to rethink how Documentation/githooks.txt\nis maintained and the list we have here is synchronized with it.\n\nThe design could me just the matter of running \"grep\" of some sort,\nwith appropriate markups that are no-op to AsciiDoctor/AsciiDoc\nadded to the documentation source, to produce this list.\n\n> +\t */\n> +\tconst char *hooks = \"applypatch-msg,\"\n> +\t\t\t    \"pre-applypatch,\"\n> +\t\t\t    \"post-applypatch,\"\n> +\t\t\t    \"pre-commit,\"\n> +\t\t\t    \"pre-merge-commit,\"\n> +\t\t\t    \"prepare-commit-msg,\"\n> +\t\t\t    \"commit-msg,\"\n> +\t\t\t    \"post-commit,\"\n> +\t\t\t    \"pre-rebase,\"\n> +\t\t\t    \"post-checkout,\"\n> +\t\t\t    \"post-merge,\"\n> +\t\t\t    \"pre-push,\"\n> +\t\t\t    \"pre-receive,\"\n> +\t\t\t    \"update,\"\n> +\t\t\t    \"post-receive,\"\n> +\t\t\t    \"post-update,\"\n> +\t\t\t    \"push-to-checkout,\"\n> +\t\t\t    \"pre-auto-gc,\"\n> +\t\t\t    \"post-rewrite,\"\n> +\t\t\t    \"sendemail-validate,\"\n> +\t\t\t    \"fsmonitor-watchman,\"\n> +\t\t\t    \"p4-pre-submit,\"\n> +\t\t\t    \"post-index-changex\";\n> +\tstruct string_list hooks_list = STRING_LIST_INIT_DUP;\n> +\tstruct string_list_item *iter = NULL;\n> +\n> +\n> +\tif (nongit) {\n> +\t\tstrbuf_addstr(hook_info,\n> +\t\t\t\"not run from a git repository - no hooks to show\\n\");\n> +\t\treturn;\n> +\t}\n> +\n> +\tstring_list_split(&hooks_list, hooks, ',', -1);\n> +\n> +\tfor_each_string_list_item(iter, &hooks_list) {\n> +\t\tif (find_hook(iter->string)) {\n> +\t\t\tstrbuf_addstr(hook_info, iter->string);\n> +\t\t\tstrbuf_complete_line(hook_info);\n> +\t\t}\n> +\t}\n> +}\n> +\n>  static const char * const bugreport_usage[] = {\n>  \tN_(\"git bugreport [-o|--output <file>]\"),\n>  \tNULL\n> @@ -193,6 +243,9 @@ int cmd_main(int argc, const char **argv)\n>  \tget_header(&buffer, \"Safelisted Config Info\");\n>  \tget_safelisted_config(&buffer);\n>  \n> +\tget_header(&buffer, \"Configured Hooks\");\n\nPhrase nit.  There may be many people who just enabled hooks without\nconfiguring, so \"Enabled Hooks\" may be more appropriate.  We do not\nhave to inspect what is in the hook to determine if it is enabled,\nbut we do need to if we want to tell if a hook is \"configured\".\n\n> +\tget_populated_hooks(&buffer, nongit_ok);\n> +\n>  \treport = fopen_for_writing(report_path.buf);\n>  \tstrbuf_write(&buffer, report);\n>  \tfclose(report);\n"},{"id":"391089","messageId":"xmqqd0au89z5.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200124033436.81097-13-emilyshaffer@google.com","subject":"Re: [PATCH v5 12/15] bugreport: count loose objects","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-04T18:48:30Z","receivedAt":"2020-02-04T18:48:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"emilyshaffer@google.com writes:\n\n> From: Emily Shaffer <emilyshaffer@google.com>\n>\n> The number of unpacked objects in a user's repository may help us\n> understand the root of the problem they're seeing, especially if a\n> command is running unusually slowly.\n>\n> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n> The refactor removed much of the code Dscho suggested; and yet it\n> remains true that he helped me while developing this commit (although\n> his suggestions didn't survive). Shall I leave the Helped-by line or\n> remove it?\n\nYou two collectively thought about viable alternatives and decided\nto reject what was not wanted in the final result, and not having\nthat rejected code was good for the project, right?  If so, I would\nsay it still is the help that deserves recognition.  After all,\nmaking the result better by removing things is harder than by adding\nthings ;-)\n\n>  bugreport.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 46 insertions(+)\n> ...\n\nThe patch text looked sensible.\n"},{"id":"391091","messageId":"xmqq8sli89eu.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200124033436.81097-14-emilyshaffer@google.com","subject":"Re: [PATCH v5 13/15] bugreport: add packed object summary","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-04T19:00:41Z","receivedAt":"2020-02-04T19:00:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"emilyshaffer@google.com writes:\n\n> From: Emily Shaffer <emilyshaffer@google.com>\n>\n> Alongside the loose object counts, it can be useful to show the number\n> of packs and packed objects. This way we can check whether the repo has\n> an appropriate ratio of packed to loose objects to help determine\n> whether it's behaving correctly.\n\nThis lets the enumeration machinery to enumerate at the individual\nobject level, relies on the enumeration machinery to show your\ncallback all objects from the same pack before an object from a\ndifferent pack, to count both objects and packs.\n\nBut given that packfiles record how many objects there are in the\npack, and that the packfile.c layer must know what are the pack\nfiles we have available, I wonder if we have an API already to allow\nus to enumerate each packfile, and while counting the number of\ntimes our callback was called, add the objects contained in each of\nthem.  If there isn't, it does not sound like a bad API function to\nadd (i.e. given a repository r, iterate over r->objects->packed_git\nand let the API caller see each of them; the API caller can grab\nnum_objects and add them up).\n\n"},{"id":"391092","messageId":"xmqq4kw6899e.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200124033436.81097-14-emilyshaffer@google.com","subject":"Re: [PATCH v5 13/15] bugreport: add packed object summary","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-04T19:03:57Z","receivedAt":"2020-02-04T19:04:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"emilyshaffer@google.com writes:\n\n> From: Emily Shaffer <emilyshaffer@google.com>\n>\n> Alongside the loose object counts, it can be useful to show the number\n> of packs and packed objects. This way we can check whether the repo has\n> an appropriate ratio of packed to loose objects to help determine\n> whether it's behaving correctly.\n\nThis step makes me wonder if we want to see the midx as well.\nDidn't we have a bug that manifests only when midx is (or is not) in\nuse?\n\nSimilarly, I think use (or non-use) of the commit graph may also be\na useful information for diagnosing.\n\n\n\n"},{"id":"391130","messageId":"20200204220032.GC87163@google.com","threadId":"52442","inReplyTo":"CAN0heSoaASfMhgLwZx4MZAdoGOfGK1fJK5X9VfUJN5R38gFVTA@mail.gmail.com","subject":"Re: [PATCH v5 01/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-04T22:00:32Z","receivedAt":"2020-02-04T22:00:40Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:18:55PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 05:56, <emilyshaffer@google.com> wrote:\n> >\n> > From: Emily Shaffer <emilyshaffer@google.com>\n> >\n> > Teach Git how to prompt the user for a good bug report: reproduction\n> > steps, expected behavior, and actual behavior. Later, Git can learn how\n> > to collect some diagnostic information from the repository.\n> \n> (\"Later\" meaning \"later in this series\", or \"any day now\"? ;-) )\n> \n> > +SYNOPSIS\n> > +--------\n> > +[verse]\n> > +'git bugreport' [-o | --output <path>]\n> \n> Hmm. Should that be \"[(-o | --output) <path>]\"?\n\nDone.\n\n> > +DESCRIPTION\n> > +-----------\n> > +Captures information about the user's machine, Git client, and repository state,\n> > +as well as a form requesting information about the behavior the user observed,\n> > +into a single text file which the user can then share, for example to the Git\n> > +mailing list, in order to report an observed bug.\n> \n> Nice description. Got it.\n> \n> > +The following information is requested from the user:\n> > +\n> > + - Reproduction steps\n> > + - Expected behavior\n> > + - Actual behavior\n> > +\n> > +The following information is captured automatically:\n> > +\n> > + - Git version (`git version --build-options`)\n> > + - Machine information (`uname -a`)\n> > + - Versions of various dependencies\n> > + - Git config contents (`git config --show-origin --list`)\n> > + - The names of all configured git-hooks in `.git/hooks/`\n> \n> I would have expected these points to appear later, both to make it\n> clear what this does commit does (and not), and to highlight what\n> user-visible (documentation-worthy) changes later commits bring along.\n\nSure, agreed.\n\n> \n> > +OPTIONS\n> > +-------\n> > +-o [<path>]::\n> > +--output [<path>]::\n> \n> Drop the \"[\" and \"]\"? If you give -o, you'd better give a path as well?\n\nDone.\n\n> > +       Place the resulting bug report file in <path> instead of the root of the\n> \n> `<path>`\n\nDone.\n\n> > +\"Please review the rest of the bug report below.\\n\"\n> > +\"You can delete any lines you don't wish to send.\\n\");\n> \n> \"send\" sounds like we're *just* about to send this report somewhere, but\n> it's \"only\" going to be written to the disk. Maybe \"share\", instead?\n\nNice turn of phrase, done.\n\n> > +       if (option_output) {\n> > +               strbuf_addstr(&report_path, option_output);\n> > +               strbuf_complete(&report_path, '/');\n> > +       }\n> \n> I thought I'd use `-o` to indicate the filename, but it turns out it's\n> the *directory* where the file (of some semi-random, generated name)\n> will end up. Re-reading the docs further up, I can see how this is\n> consistent. I sort of wonder if this should be `--output*-directory*`\n> for symmetry with `git format-patch`.\n\nSure.\n\n> > +       strbuf_addstr(&report_path, \"git-bugreport-\");\n> > +       strbuf_addftime(&report_path, \"%F\", gmtime(&now), 0, 0);\n> > +       strbuf_addstr(&report_path, \".txt\");\n> > +\n> > +\n> \n> (Double blank line?)\n\nDone.\n \n> > +       get_bug_template(&buffer);\n> > +\n> > +       report = fopen_for_writing(report_path.buf);\n> \n> Report might be NULL here.\n\nNice.\n\n> If there's already such a file, we overwrite. Should we generate the\n> filename using not just today's date (two bug reports in a day wouldn't\n> be unheard of?) but also something like hh:mm:ss?\n\nSure. For the sake of brevity I'll probably neglect seconds; I hope\nsomeone is spending more than 1 minute filling in the provided form.\n\nI'm a little worried about including : in a filename, so I went for\n'git-bugreport-YYYY-MM-DD-HHMM' (24-hour).\n\nAs I started to write a test to ensure duplicate filenames were handled\nwell, Jonathan Tan pointed out that it would be easy to add an arg like\n--suffix to allow specifying a custom strftime string. That would allow\nusers to easily create a file named\n`git-bugreport-fetch-failing.txt` or `git-bugreport-March-19.txt` or\nwhatever they want; it also makes testing easy. So I'll add this for the\nnext rollup.\n\n> \n> > +       strbuf_write(&buffer, report);\n> > +       fclose(report);\n> \n> Maybe clear the strbuf around here...\n> \n> > +       launch_editor(report_path.buf, NULL, NULL);\n> > +       return 0;\n> \n> ... and/or UNLEAK it here, together with report_path.\n> \n> Maybe \"return -launch_editor(...)\"?\n\nHm, sure. I see that builtin/tag.c does mark strbufs this way, so I\ndon't see a problem using UNLEAK and tail-calling launch_editor().\n\n\nAs a final bonus, I also added a line to report to stderr the name of\nthe file that was created. I noticed it's sort of unclear what the\ncommand actually did otherwise.\n\n> > +#!/bin/bash\n> \n> Use /bin/sh instead?\n\nYeah, doing so immediately pointed out the bashisms you mentioned, plus\nsome more. :facepalm:\n\n> \n> > +# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n> > +# information there; we can make sure all our headers were followed by some\n> > +# information to check if the command was successful.\n> > +HEADER_PATTERN=\"^\\[.*\\]$\"\n> > +check_all_headers_populated() {\n> > +       while read -r line; do\n> > +               if [$(grep $HEADER_PATTERN $line)]; then\n> \n> I think this is a bash-ism.\n> \n> > +                       read -r nextline\n> > +                       if [-z $nextline]; then\n> \n> Likewise.\n> \n> > +                               return 1;\n> > +                       fi\n> > +               fi\n> > +       done\n> > +}\n> > +\n> > +test_expect_success 'creates a report with content in the right places' '\n> > +       git bugreport &&\n> > +       check_all_headers_populated <git-bugreport-* &&\n> > +       rm git-bugreport-*\n> > +'\n> > +\n> > +test_expect_success '--output puts the report in the provided dir' '\n> > +       mkdir foo/ &&\n> \n> If foo isn't there, do we not create it? Apparently not -- in my\n> testing, we segfault. (We don't check for NULL after opening the file.)\n\nYeah, at the moment I just added a die() if we can't open the provided\npath. I think other utilties can create the path (e.g. git-format-patch)\nbut where it makes sense to do so, I'd prefer to keep bugreport very\nsimple.\n\nI'll die instead of overwriting, too; you're right that spending quite a\nwhile on a bug report and then accidentally writing over it with a blank\none would be a very bad user experience.\n\n> \n> > +       git bugreport -o foo/ &&\n> > +       test -f foo/git-bugreport-* &&\n> \n> test_path_is_file\n\nSure.\n\n> > +       rm -fr foo/\n> > +'\n> > +\n> > +test_expect_success 'incorrect arguments abort with usage' '\n> > +       test_must_fail git bugreport --false 2>output &&\n> > +       grep usage output &&\n> > +       test ! -f git-bugreport-*\n> \n> test_path_is_missing\n\nOK.\n\nThanks very much, Martin, for the thorough review. This is incredibly\nhelpful.\n\n - Emily\n"},{"id":"391132","messageId":"20200204222137.GD87163@google.com","threadId":"52442","inReplyTo":"CAN0heSqaeaBTCmiY=f0eD8=hsPV7BL9OCFL=Oq7je+t_o4frqA@mail.gmail.com","subject":"Re: [PATCH v5 03/15] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-04T22:21:37Z","receivedAt":"2020-02-04T22:21:46Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:19:55PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> > +static void get_system_info(struct strbuf *sys_info)\n> > +{\n> > +       struct strbuf version_info = STRBUF_INIT;\n> > +\n> > +       /* get git version from native cmd */\n> > +       strbuf_addstr(sys_info, \"git version:\\n\");\n> > +       get_version_info(&version_info, 1);\n> > +       strbuf_addbuf(sys_info, &version_info);\n> > +       strbuf_complete_line(sys_info);\n> \n> This leaks version_info.\n\nSo it does.\n\nI think the easiest thing is to drop the 'strbuf_reset()' at the top of\nhelp.c:get_version_info(), and just pass in sys_info from bugreport.c.\n\n - Emily\n"},{"id":"391134","messageId":"20200204225118.GE87163@google.com","threadId":"52442","inReplyTo":"CAN0heSoh87_16y+B5=UXAhbaVnejmRj3XXjy5viABheBz+D3fA@mail.gmail.com","subject":"Re: [PATCH v5 06/15] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-04T22:51:18Z","receivedAt":"2020-02-04T22:51:26Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:21:39PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> > +#else\n> > +\n> > +static inline void get_compiler_info(struct strbuf *info)\n> > +{\n> > +       strbuf_addstr(info, \"get_compiler_info() not implemented\");\n> \n> Maybe \"no compiler info available\" (or s/ available//, or\n> s/available/reported/), or something else more human-readable?\n\nHm. I envisioned the target audience for this as \"Git developers\" (and\nthat's why I didn't mark the unimplemented string for translation); Git\ndevelopers know exactly what \"get_compiler_info() not implemented\"\nmeans. But I suppose it's just as easy to grep for one string as the\nother.\n\nI am hesitant to say \"no info available\" or \"no info reported\" when I'm\ncertain there is some environment variable set at build time which\ncontains the info we'd want to show here; it really is just a question\nof some Git developer having put in the time to implement this function.\n\nSo, I think I will leave it. Thanks for your suggestions.\n\n - Emily\n"},{"id":"391135","messageId":"20200204225428.GF87163@google.com","threadId":"52442","inReplyTo":"CAN0heSqiMvMopqpMrnOffsO-nZ6UPWbuHQdB9VxLhWhm-d95rA@mail.gmail.com","subject":"Re: [PATCH v5 07/15] bugreport: add curl version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-04T22:54:28Z","receivedAt":"2020-02-04T22:54:35Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:27:45PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:41, <emilyshaffer@google.com> wrote:\n> > +static void get_curl_version_info(struct strbuf *curl_info)\n> > +{\n> > +       struct child_process cp = CHILD_PROCESS_INIT;\n> > +\n> > +       argv_array_push(&cp.args, \"git\");\n> > +       argv_array_push(&cp.args, \"remote-https\");\n> > +       argv_array_push(&cp.args, \"--build-info\");\n> > +       if (capture_command(&cp, curl_info, 0))\n> > +           strbuf_addstr(curl_info, \"'git-remote-https --build-info' not supported\\n\");\n> > +}\n> >\n> >  static void get_system_info(struct strbuf *sys_info)\n> >  {\n> > @@ -31,6 +43,10 @@ static void get_system_info(struct strbuf *sys_info)\n> >         strbuf_addstr(sys_info, \"compiler info: \");\n> >         get_compiler_info(sys_info);\n> >         strbuf_complete_line(sys_info);\n> > +\n> > +       strbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n> > +       get_curl_version_info(sys_info);\n> \n> The header here looks a lot like an implementation detail of\n> `get_curl_version_info()`. Or put differently, these risk getting out of\n> sync. Maybe frame the header a bit more human readable: \"curl version\".\n> But is this \"curl version\", or more like \"git-remote-https version\"?\n> There's some discrepancy here.\n\nHm, I think you're saying \"If we switch to future-https-lib instead of\ncURL for git-remote-https, then this command will be incorrectly named.\"\nSure, I agree. It's true that with this change git-remote-https also\ntells us some info about itself.\n\nThanks.\n - Emily\n"},{"id":"391136","messageId":"20200204231602.GG87163@google.com","threadId":"52442","inReplyTo":"CAN0heSq9AdF_WPmSkxDA3cPzOQBAbuw4oa+8azvLtjbP-jQfKw@mail.gmail.com","subject":"Re: [PATCH v5 08/15] bugreport: include user interactive shell","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-04T23:16:02Z","receivedAt":"2020-02-04T23:16:09Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:28:40PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:41, <emilyshaffer@google.com> wrote:\n> > +       char *shell = NULL;\n> \n> (Unnecessary initialization.)\n> \n> > +       shell = getenv(\"SHELL\");\n> > +       strbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n> > +                   shell ? shell : \"(NULL)\");\n> \n> Thanks for avoiding a classic pitfall. :-)\n\nThank Junio. I fell right into it because it Just Works in gcc. ;)\n\n> \"<unused>\" instead of \"(NULL)\"? \"NULL\" is mostly an implementation\n> detail.\n\nSure, why not.\n"},{"id":"391143","messageId":"20200205003043.GH87163@google.com","threadId":"52442","inReplyTo":"CAN0heSo2ujJr_Mi5xPv86NneLoXT3DM3dnRmTACs2VQERBq76Q@mail.gmail.com","subject":"Re: [PATCH v5 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T00:30:43Z","receivedAt":"2020-02-05T00:30:52Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Jan 31, 2020 at 10:20:05PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:35, <emilyshaffer@google.com> wrote:\n> > Add a new step to the build to generate a safelist of git-config\n> > variables which are appropriate to include in the output of\n> > git-bugreport. New variables can be added to the safelist by annotating\n> > their documentation in Documentation/config with the\n> > \"bugreport\" macro, which is recognized by AsciiDoc and\n> > AsciiDoctor.\n> \n> \"which is recognized by\" sounds like it's built-in. Maybe \"with a new\n> no-op 'bugreport' macro\" or something like that.\n\nSure, I'll wordsmith this a little.\n\n> \n> > -sendemail.signedoffcc (deprecated)::\n> > +sendemail.signedoffcc (deprecated) bugreport:exclude[x] ::\n> >         Deprecated alias for `sendemail.signedoffbycc`.\n> >\n> > -sendemail.smtpBatchSize::\n> > +sendemail.smtpBatchSize bugreport:include[x] ::\n> >         Number of messages to be sent per connection, after that a relogin\n> >         will happen.  If the value is 0 or undefined, send all messages in\n> >         one connection.\n> >         See also the `--batch-size` option of linkgit:git-send-email[1].\n> \n> Do we really need to list includes *and* excludes?\n\nNeed? Nah. The exclude markers are not even acknowledged by the current\nimplementation.\n\n> I could see the point of adding an exclude here and there to signal\n> that \"this might look innocent enough, but trust me, we really need to\n> exclude this\" in order to avoid future commits to more or less\n> accidentally over-include.\n\nThis was more of my line of thinking, along with the thought that some\nfolks may use bug reporting internally, where they have A) more control\nover which extensions/tools are in use, and B) less concern about\nsharing things like remote URLs, branch names, etc. and may want to go\nfor a blocklist as opposed to a safelist, to make it easier for their\nsupport folks to diagnose.\n\n> Should we add some internal documentation and/or a remark in the commit\n> message about this? As an example, is \"sendemail.signedofcc\" sensitive\n> enough that we need to explicitly exclude it? If someone wants to come\n> along and include it, they don't just need to argue for an inclusion,\n> but also for lifting the exclusion. Hmm?\n\nYeah, I think this is a good point. I'll try to figure out how to reword\nthe commit message, and take another look at the sample include/exclude\nchange I made to see where I can omit entirely.\n\n - Emily\n"},{"id":"391144","messageId":"20200205004455.GI87163@google.com","threadId":"52442","inReplyTo":"CAN0heSq_i4EitqYH-qrZyXBU+=PUNcSXOOJDHLSnJ1ufV0WtaQ@mail.gmail.com","subject":"Re: [PATCH v5 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T00:44:55Z","receivedAt":"2020-02-05T00:45:02Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:34:24PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:35, <emilyshaffer@google.com> wrote:\n> > Add a new step to the build to generate a safelist of git-config\n> > variables which are appropriate to include in the output of\n> > git-bugreport. New variables can be added to the safelist by annotating\n> > their documentation in Documentation/config with the\n> > \"bugreport\" macro, which is recognized by AsciiDoc and\n> > AsciiDoctor.\n> >\n> > Some configs are private in nature, and can contain remote URLs,\n> > passwords, or other sensitive information. In the event that a user\n> > doesn't notice their information while reviewing a bugreport, that user\n> > may leak their credentials to other individuals, mailing lists, or bug\n> > tracking tools inadvertently. Heuristic blocklisting of configuration\n> > keys is imperfect and prone to false negatives; given the nature of the\n> > information which can be leaked, a safelist is more reliable.\n> \n> I sort of wonder whether safelist/blocklist is to prefer over\n> whitelist/blacklist, or if it's the other way round. The former are new\n> to me, whereas the latter are the terms I would have used. But that's\n> just me, of course. I was a little surprised, that's all.\n\nEh. I think the following things are true:\n\n - Whitelist/blacklist has a \"smell\" of discrimination, whether that's\n   the true etymology or not.\n - Those with experience in the field can easily understand what\n   whitelist or blacklist means.\n - Safelist/blocklist do not \"smell\" the same way.\n - It is easy to tell what \"safelist\" means: \"a list of stuff which is\n   safe.\" No experience needed.\n\nSo, while it's new, I think it's not harmful. I see only a no-op or\npositive impact from using this term instead of whitelist/blacklist.\nComputer science seems to have quite a few terms which fall into this\nlong-standing but potentially negative area, so I don't mind looking for\nalternatives where it's harmless to do so.\n\n> \n> > Implement a new no-op \"bugreport\" macro for use as\n> > \"bugreport:include[x]\" to annotate the config keys that should be\n> > included in the automatically generated safelist. Use \"exclude\" for the\n> > others.\n> >\n> > With Asciidoctor, it's ok to say \"bugreport:include[]\", but AsciiDoc\n> > seems to want something between the brackets. A bit unfortunate, but\n> > not a huge problem -- we'll just provide an \"x\".\n> \n> I recognize this reasoning :-) and I'm not terribly opposed to it, but\n> after some nights' sleeping on this, I have to wonder if\n> \"annotate:bugreport[include]\" wouldn't be better than \"bugreport[x]\"\n> with that ugly \"x\". Maybe this isn't the biggest problem, but if we\n> expect this macro to eventually sit right next to ~90% of all our config\n> variables...\n\nHm. I wanted to say, \"Ok, but I don't know how to do that, so can you\nhelp?\" But I think that's all the more reason that I should do it ;)\n\nOk. I will try and change it to annotate:bugreport[include] like you\nsuggested, and hopefully learn more about asciidoc macros :)\n\n> \n> > \"doc-diff\" reports that this macro doesn't render at all. That is,\n> > these are both empty after this commit:\n> >\n> >   cd Documentation\n> >   ./doc-diff --asciidoctor :/\"bugreport: add tool\" HEAD\n> >   ./doc-diff --asciidoc    :/\"bugreport: add tool\" HEAD\n> \n> That was true in [1], but alas, no more. In that patch, it's sort of\n> obvious from the diff how it adds a \"class\" which \"end\"s.\n> \n> [1] https://lore.kernel.org/git/20190817203846.31609-1-martin.agren@gmail.com/\n> \n> > --- a/Documentation/asciidoctor-extensions.rb\n> > +++ b/Documentation/asciidoctor-extensions.rb\n> > @@ -37,6 +37,10 @@ module Git\n> >            output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n> >          end\n> >          output\n> > +\n> > +    class BugReportProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n> > +      def process(parent, action, attrs)\n> > +        \"\"\n> >        end\n> >      end\n> >    end\n> \n> But this one doesn't add an \"end\", and Asciidoctor trips up badly.\n\nOk, I'll have a look. I'm sure I copied something badly.\n\n> \n> > +  # The bugreport macro does nothing as far as rendering is\n> > +  # concerned -- we just grep for it in the sources.\n> > +  inline_macro Git::Documentation::BugReportProcessor, :bugreport\n> \n> (I never much liked this copy-paste comment then, and I still don't, to\n> be honest.)\n\nI'll see if I can find a reasonable alternative (or remove it).\n\n - Emily\n"},{"id":"391145","messageId":"20200205005237.GJ87163@google.com","threadId":"52442","inReplyTo":"20200205003043.GH87163@google.com","subject":"Re: [PATCH v5 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T00:52:37Z","receivedAt":"2020-02-05T00:52:44Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 04, 2020 at 04:30:43PM -0800, Emily Shaffer wrote:\n> Yeah, I think this is a good point. I'll try to figure out how to reword\n> the commit message, and take another look at the sample include/exclude\n> change I made to see where I can omit entirely.\n\nEh. I'm going to try and reword the whole commit message. I combined\nyour scissors patch, plus something from Dscho's scissors patch, plus my\noriginal commit message, and now it's huge and hard to follow.\n\n\n - Emily\n"},{"id":"391146","messageId":"20200205013405.GK87163@google.com","threadId":"52442","inReplyTo":"CAN0heSr3WTtGh=gWTiXYEoSGGHPF_YniA9xH989=OtYfM2-Evw@mail.gmail.com","subject":"Re: [PATCH v5 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T01:34:05Z","receivedAt":"2020-02-05T01:34:13Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Jan 30, 2020 at 11:36:43PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> > --- a/Makefile\n> > +++ b/Makefile\n> > @@ -2465,7 +2465,7 @@ endif\n> >  git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n> >         $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n> >\n> > -git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n> > +git-bugreport$X: bugreport-config-safelist.h bugreport.o GIT-LDFLAGS $(GITLIBS)\n> >         $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n> >                 $(LIBS)\n> \n> Haven't looked at this patch at all, except I've noticed that something\n> is up with the dependencies. I think bugreport.o needs to depend on\n> bugreport-config-safelist.h. As it is, the latter may or may not be\n> available as bugreport.o is built. (Reproduces fairly well for me with\n> something like `make clean && make -j16`.)\n\nHum, I thought that the ordering of the dependency list here was\nensured. But I see where help.o relies directly on command-list.h, so\nI'll add a dependency for bugreport.o (and drop it from the direct\ndependency for git-bugreport).\n\n - Emily\n"},{"id":"391148","messageId":"20200205023127.GL87163@google.com","threadId":"52442","inReplyTo":"CAN0heSo_Ois83gqNrHvNn2HSMMTXvKShxTb_RdG2qY6D7rnthA@mail.gmail.com","subject":"Re: [PATCH v5 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T02:31:27Z","receivedAt":"2020-02-05T02:31:35Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Jan 31, 2020 at 10:25:06PM +0100, Martin Ågren wrote:\n> On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> > Taking the build-time generated array and putting it into a set saves us\n> > time - since git_config_bugreport() is called for every option the user\n> > has configured, performing option lookup in constant time is a useful\n> > optimization.\n> \n> I'm sympathetic to your sending out what you have to obtain comments,\n> knowing that it's not perfect. It would have saved me some time and\n> effort if I'd known that this was the case though. An \"[RFC]\" tag,\n> perhaps. Or at least tweaking the above part of this commit message to\n> say that this might be over-engineered, with a reference to [1].\n> \n> [1] https://lore.kernel.org/git/20200124032905.GA37541@google.com/\n\nYeah, you are right, and thanks for the feedback. I think I had wrapped\nup the series before I realized there were those significant outstanding\ncomments, but I definitely should have said so in this patch.\n\n> \n> > +       int safelist_len = sizeof(bugreport_config_safelist) / sizeof(const char *);\n> \n> I was going to suggest ARRAY_SIZE, but then I realized there are some\n> outstanding questions around whether you need this stuff in the first\n> place. I'd be inclined to guess that the first version of this would be\n> \"for each safelisted item, obtain it and include\", ignoring any \"a.*.b\"\n> business. In which case you wouldn't really need this hashset stuff.\n\nRegardless, I think it's worth doing nicely for now.\n\nIt seems to me that supporting wildcarding in the config safelist is a\nsuperset of supporting static strings in that safelist - that is, if I\nwrite it simply to support static strings, a later change to support\nwildcards would be welcome and non-breaking.\n\nSo I'm going to clean this up without making it more featureful, for\nnow.\n\nSorry about the confusion!\n - Emily\n"},{"id":"391150","messageId":"20200205024859.GM87163@google.com","threadId":"52442","inReplyTo":"xmqqh8068a5k.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 11/15] bugreport: collect list of populated hooks","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T02:48:59Z","receivedAt":"2020-02-05T02:49:47Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 04, 2020 at 10:44:39AM -0800, Junio C Hamano wrote:\n> emilyshaffer@google.com writes:\n> \n> > +\t/*\n> > +\t * Doesn't look like there is a list of all possible hooks; so below is\n> > +\t * a transcription of `git help hook`.\n> \n> That's \"git help hooks\", if I tried my reproduction correctly.\n\nYep. I'll fix it.\n\n> A straight-forward (in the sense of \"what we want in the outcome is\n> quite clear\" and not in the sense of \"anybody can design and implement\n> it with a single 30-line patch\") follow-up we can make after this\n> series lands is to rethink how Documentation/githooks.txt is\n> maintained and the list we have here is synchronized with it.\n> \n> The design could me just the matter of running \"grep\" of some sort,\n> with appropriate markups that are no-op to AsciiDoctor/AsciiDoc\n> added to the documentation source, to produce this list.\n\nWell, with Martin's suggestion[1] to use annotate:bugreport[include]\ninstead of bugreport:include[x], this kind of change becomes a matter of\ncourse to just use \"annotate:hook[x]\" and write a script nearly\nidentical to generate-bugreport-config-safelist.sh, and add it to the\nMakefile.\n\nLike I said up-thread, I don't like the idea just because it's awfully\ntemporary (pending work that's right below this on my list for the\ncoming weeks).\n\nIt sounds like you're saying you don't mind any work of this nature\nbeing done as a follow-up - and that's fine with me, too. I'd just\nrather do the follow-up with enums and a library than with grep and\nsh. :)\n\n> >  static const char * const bugreport_usage[] = {\n> >  \tN_(\"git bugreport [-o|--output <file>]\"),\n> >  \tNULL\n> > @@ -193,6 +243,9 @@ int cmd_main(int argc, const char **argv)\n> >  \tget_header(&buffer, \"Safelisted Config Info\");\n> >  \tget_safelisted_config(&buffer);\n> >  \n> > +\tget_header(&buffer, \"Configured Hooks\");\n> \n> Phrase nit.  There may be many people who just enabled hooks without\n> configuring, so \"Enabled Hooks\" may be more appropriate.  We do not\n> have to inspect what is in the hook to determine if it is enabled,\n> but we do need to if we want to tell if a hook is \"configured\".\n\nAh, that's a good point. OK, I'll change the wording as you suggested.\n\n - Emily\n"},{"id":"391151","messageId":"20200205025026.GN87163@google.com","threadId":"52442","inReplyTo":"xmqqd0au89z5.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 12/15] bugreport: count loose objects","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T02:50:26Z","receivedAt":"2020-02-05T02:50:35Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 04, 2020 at 10:48:30AM -0800, Junio C Hamano wrote:\n> emilyshaffer@google.com writes:\n> \n> > From: Emily Shaffer <emilyshaffer@google.com>\n> >\n> > The number of unpacked objects in a user's repository may help us\n> > understand the root of the problem they're seeing, especially if a\n> > command is running unusually slowly.\n> >\n> > Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> > Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> > ---\n> > The refactor removed much of the code Dscho suggested; and yet it\n> > remains true that he helped me while developing this commit (although\n> > his suggestions didn't survive). Shall I leave the Helped-by line or\n> > remove it?\n> \n> You two collectively thought about viable alternatives and decided\n> to reject what was not wanted in the final result, and not having\n> that rejected code was good for the project, right?  If so, I would\n> say it still is the help that deserves recognition.  After all,\n> making the result better by removing things is harder than by adding\n> things ;-)\n\nSounds great to me. I'd rather over-assign credit than under-assign (but\nI don't think this is a case of over-assigning here).\n\n> >  bugreport.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++\n> >  1 file changed, 46 insertions(+)\n> > ...\n> \n> The patch text looked sensible.\n\nThanks.\n\n - Emily\n"},{"id":"391152","messageId":"20200205030016.GO87163@google.com","threadId":"52442","inReplyTo":"20200205024859.GM87163@google.com","subject":"Re: [PATCH v5 11/15] bugreport: collect list of populated hooks","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T03:00:16Z","receivedAt":"2020-02-05T03:00:24Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 04, 2020 at 06:48:59PM -0800, Emily Shaffer wrote:\n> Well, with Martin's suggestion[1] to use annotate:bugreport[include]\n> instead of bugreport:include[x], this kind of change becomes a matter of\n> course to just use \"annotate:hook[x]\" and write a script nearly\n> identical to generate-bugreport-config-safelist.sh, and add it to the\n> Makefile.\n\nBah.\n\n[1]: https://lore.kernel.org/git/CAN0heSq_i4EitqYH-qrZyXBU+=PUNcSXOOJDHLSnJ1ufV0WtaQ@mail.gmail.com\n"},{"id":"391153","messageId":"20200205030949.GP87163@google.com","threadId":"52442","inReplyTo":"xmqq4kw6899e.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 13/15] bugreport: add packed object summary","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T03:09:49Z","receivedAt":"2020-02-05T03:09:57Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 04, 2020 at 11:03:57AM -0800, Junio C Hamano wrote:\n> emilyshaffer@google.com writes:\n> \n> > From: Emily Shaffer <emilyshaffer@google.com>\n> >\n> > Alongside the loose object counts, it can be useful to show the number\n> > of packs and packed objects. This way we can check whether the repo has\n> > an appropriate ratio of packed to loose objects to help determine\n> > whether it's behaving correctly.\n> \n> This step makes me wonder if we want to see the midx as well.\n> Didn't we have a bug that manifests only when midx is (or is not) in\n> use?\n> \n> Similarly, I think use (or non-use) of the commit graph may also be\n> a useful information for diagnosing.\n> \n\nSure. I'll look into both of these. Would you rather see them as add-ons\nlater, or do you want me to hold off on a v6 of this set until they're\nready?\n\n - Emily\n"},{"id":"391154","messageId":"20200205031524.GQ87163@google.com","threadId":"52442","inReplyTo":"xmqq8sli89eu.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 13/15] bugreport: add packed object summary","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-05T03:15:24Z","receivedAt":"2020-02-05T03:15:31Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 04, 2020 at 11:00:41AM -0800, Junio C Hamano wrote:\n> emilyshaffer@google.com writes:\n> \n> > From: Emily Shaffer <emilyshaffer@google.com>\n> >\n> > Alongside the loose object counts, it can be useful to show the number\n> > of packs and packed objects. This way we can check whether the repo has\n> > an appropriate ratio of packed to loose objects to help determine\n> > whether it's behaving correctly.\n> \n> This lets the enumeration machinery to enumerate at the individual\n> object level, relies on the enumeration machinery to show your\n> callback all objects from the same pack before an object from a\n> different pack, to count both objects and packs.\n> \n> But given that packfiles record how many objects there are in the\n> pack, and that the packfile.c layer must know what are the pack\n> files we have available, I wonder if we have an API already to allow\n> us to enumerate each packfile, and while counting the number of\n> times our callback was called, add the objects contained in each of\n> them.  If there isn't, it does not sound like a bad API function to\n> add (i.e. given a repository r, iterate over r->objects->packed_git\n> and let the API caller see each of them; the API caller can grab\n> num_objects and add them up).\n\nYeah, I don't see one. I'll go ahead and add it - that sounds\nstraightforward enough.\n\n - Emily\n"},{"id":"391185","messageId":"CAN0heSpe8L6v+z49PixRwyYrCncS6CjdJAJVKaS+L5NkOPNgTg@mail.gmail.com","threadId":"52442","inReplyTo":"20200204225118.GE87163@google.com","subject":"Re: [PATCH v5 06/15] bugreport: add compiler info","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-02-05T19:47:28Z","receivedAt":"2020-02-05T19:47:41Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Tue, 4 Feb 2020 at 23:51, Emily Shaffer <emilyshaffer@google.com> wrote:\n>\n> On Thu, Jan 30, 2020 at 11:21:39PM +0100, Martin Ågren wrote:\n> > On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> > > +#else\n> > > +\n> > > +static inline void get_compiler_info(struct strbuf *info)\n> > > +{\n> > > +       strbuf_addstr(info, \"get_compiler_info() not implemented\");\n> >\n> > Maybe \"no compiler info available\" (or s/ available//, or\n> > s/available/reported/), or something else more human-readable?\n>\n> Hm. I envisioned the target audience for this as \"Git developers\" (and\n> that's why I didn't mark the unimplemented string for translation); Git\n> developers know exactly what \"get_compiler_info() not implemented\"\n> means. But I suppose it's just as easy to grep for one string as the\n> other.\n>\n> I am hesitant to say \"no info available\" or \"no info reported\" when I'm\n> certain there is some environment variable set at build time which\n> contains the info we'd want to show here; it really is just a question\n> of some Git developer having put in the time to implement this function.\n>\n> So, I think I will leave it. Thanks for your suggestions.\n\nOk, that makes sense.\n\nMartin\n"},{"id":"391186","messageId":"CAN0heSq89F+Z+osLFQBrQEZAEEnfK19tpana044WZ6BYPKi9OQ@mail.gmail.com","threadId":"52442","inReplyTo":"20200205004455.GI87163@google.com","subject":"Re: [PATCH v5 09/15] bugreport: generate config safelist based on docs","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-02-05T19:53:15Z","receivedAt":"2020-02-05T19:53:28Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Wed, 5 Feb 2020 at 01:45, Emily Shaffer <emilyshaffer@google.com> wrote:\n>\n> > I sort of wonder whether safelist/blocklist is to prefer over\n> > whitelist/blacklist, or if it's the other way round. The former are new\n> > to me, whereas the latter are the terms I would have used. But that's\n> > just me, of course. I was a little surprised, that's all.\n>\n> Eh. I think the following things are true:\n>\n>  - Whitelist/blacklist has a \"smell\" of discrimination, whether that's\n>    the true etymology or not.\n>  - Those with experience in the field can easily understand what\n>    whitelist or blacklist means.\n>  - Safelist/blocklist do not \"smell\" the same way.\n>  - It is easy to tell what \"safelist\" means: \"a list of stuff which is\n>    safe.\" No experience needed.\n>\n> So, while it's new, I think it's not harmful. I see only a no-op or\n> positive impact from using this term instead of whitelist/blacklist.\n> Computer science seems to have quite a few terms which fall into this\n> long-standing but potentially negative area, so I don't mind looking for\n> alternatives where it's harmless to do so.\n\nOk, that all makes sense.\n\nThanks\nMartin\n"},{"id":"391188","messageId":"xmqqmu9w6bop.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"CAN0heSq9AdF_WPmSkxDA3cPzOQBAbuw4oa+8azvLtjbP-jQfKw@mail.gmail.com","subject":"Re: [PATCH v5 08/15] bugreport: include user interactive shell","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-05T20:06:46Z","receivedAt":"2020-02-05T20:06:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Ågren <martin.agren@gmail.com> writes:\n\n> On Fri, 24 Jan 2020 at 04:41, <emilyshaffer@google.com> wrote:\n>> +       char *shell = NULL;\n>\n> (Unnecessary initialization.)\n>\n>> +       shell = getenv(\"SHELL\");\n>> +       strbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n>> +                   shell ? shell : \"(NULL)\");\n>\n> Thanks for avoiding a classic pitfall. :-)\n>\n> \"<unused>\" instead of \"(NULL)\"? \"NULL\" is mostly an implementation\n> detail.\n\nIsn't that <unset>?\n"},{"id":"391191","messageId":"CAN0heSpkjACrgz8T=-VoQxgMZhMM-oSSpVz4HAPB27b_h3fGpA@mail.gmail.com","threadId":"52442","inReplyTo":"20200205023127.GL87163@google.com","subject":"Re: [PATCH v5 10/15] bugreport: add config values from safelist","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-02-05T20:12:42Z","receivedAt":"2020-02-05T20:12:56Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Wed, 5 Feb 2020 at 03:31, Emily Shaffer <emilyshaffer@google.com> wrote:\n>\n> On Fri, Jan 31, 2020 at 10:25:06PM +0100, Martin Ågren wrote:\n> > On Fri, 24 Jan 2020 at 04:40, <emilyshaffer@google.com> wrote:\n> > > Taking the build-time generated array and putting it into a set saves us\n> > > time - since git_config_bugreport() is called for every option the user\n> > > has configured, performing option lookup in constant time is a useful\n> > > optimization.\n> >\n> > I'm sympathetic to your sending out what you have to obtain comments,\n> > knowing that it's not perfect. It would have saved me some time and\n> > effort if I'd known that this was the case though. An \"[RFC]\" tag,\n> > perhaps. Or at least tweaking the above part of this commit message to\n> > say that this might be over-engineered, with a reference to [1].\n> >\n> > [1] https://lore.kernel.org/git/20200124032905.GA37541@google.com/\n>\n> Yeah, you are right, and thanks for the feedback. I think I had wrapped\n> up the series before I realized there were those significant outstanding\n> comments, but I definitely should have said so in this patch.\n>\n> >\n> > > +       int safelist_len = sizeof(bugreport_config_safelist) / sizeof(const char *);\n> >\n> > I was going to suggest ARRAY_SIZE, but then I realized there are some\n> > outstanding questions around whether you need this stuff in the first\n> > place. I'd be inclined to guess that the first version of this would be\n> > \"for each safelisted item, obtain it and include\", ignoring any \"a.*.b\"\n> > business. In which case you wouldn't really need this hashset stuff.\n>\n> Regardless, I think it's worth doing nicely for now.\n>\n> It seems to me that supporting wildcarding in the config safelist is a\n> superset of supporting static strings in that safelist - that is, if I\n> write it simply to support static strings, a later change to support\n> wildcards would be welcome and non-breaking.\n\nYeah, agreed. Also, whatever magic the code for gathering the config\nitems knows, the annotations in Documentation/, i.e., the generated list\nin bugreport-config-safelist.h will be \"synced\". That is, until we know\nhow to handle \"a.*.b\" in the safelist, we probably won't be marking\n\"a.*.b\" as safe. And even if we have some crazy mixed build, it's a\n*safe*list, so we should be fine. (Famous last words?)\n\nOn that topic though, and just so we don't mess up from the beginning,\nin the documentation, we typically write something like\n\"branch.<name>.merge\", i.e., not \"branch.*.merge\". So I guess the\n\"a.*.b\" feature would be more like \"look for '.<', something, something,\n'>.'.\" Would that be sufficient? Or would we actually want more\nfine-grained control, i.e., something like regexes?\n\nIf so, we'd need to provide those regexes somehow, e.g., as part of the\nasciidoc macro notation. :-/ Do we need to prepare somehow for such a\nfuture? I don't think we do.\n\n> So I'm going to clean this up without making it more featureful, for\n> now.\n>\n> Sorry about the confusion!\n>  - Emily\n\nNo worries. :)\n\nMartin\n"},{"id":"391192","messageId":"CAN0heSpXcuBRjQvAwPpS6bM7gBs1LQQZggJBEgLOGCXM6GSrqQ@mail.gmail.com","threadId":"52442","inReplyTo":"xmqqmu9w6bop.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 08/15] bugreport: include user interactive shell","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2020-02-05T20:14:07Z","receivedAt":"2020-02-05T20:14:20Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On Wed, 5 Feb 2020 at 21:06, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Martin Ågren <martin.agren@gmail.com> writes:\n>\n> > On Fri, 24 Jan 2020 at 04:41, <emilyshaffer@google.com> wrote:\n> >> +       char *shell = NULL;\n> >\n> > (Unnecessary initialization.)\n> >\n> >> +       shell = getenv(\"SHELL\");\n> >> +       strbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n> >> +                   shell ? shell : \"(NULL)\");\n> >\n> > Thanks for avoiding a classic pitfall. :-)\n> >\n> > \"<unused>\" instead of \"(NULL)\"? \"NULL\" is mostly an implementation\n> > detail.\n>\n> Isn't that <unset>?\n\nHeh, yes, \"SHELL: unused\" sounds wrong. :-)\n\nMartin\n"},{"id":"391218","messageId":"20200206004108.261317-1-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200124033436.81097-1-emilyshaffer@google.com","subject":"[PATCH v6 00/15] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:40:53Z","receivedAt":"2020-02-06T00:41:24Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"This patchset is based on mr/show-config-scope.\n\nSince v5, I addressed comments from Martin and Junio.\n\n - Reorganized the series so the ecosystem cleanup comes before the\n   interesting new features.\n - Spread out manpage updates to indicate each new feature as it's added.\n - Fixed a number of patches which assumed a repo, so bugreport can now\n   run anywhere.\n - Wordsmithing in the report template.\n - die() instead of overwriting an existing report.\n - Added --suffix to allow user to change the name of the report to\n   git-bugreport-<strftime format>.txt.\n - General NULL-ptr, leak, and bashism cleanup.\n - Changed safelist macro from bugreport:include[x] to\n   annotate:bugreport[include].\n - Use git_config_get_value_multi() instead of a config callback to\n   gather the safelist configs.\n - Added a convenience for_each_pack() macro to object-store.h and began\n   using it in packfile.c and bugreport.c for pack summary\n\nEmily Shaffer (15):\n  help: move list_config_help to builtin/help\n  help: add shell-path to --build-options\n  bugreport: add tool to generate debugging info\n  bugreport: gather git version and build info\n  bugreport: add uname info\n  bugreport: add compiler info\n  bugreport: add git-remote-https version\n  bugreport: include user interactive shell\n  bugreport: generate config safelist based on docs\n  bugreport: add config values from safelist\n  bugreport: collect list of populated hooks\n  bugreport: count loose objects\n  bugreport: add packed object summary\n  bugreport: list contents of $OBJDIR/info\n  bugreport: summarize contents of alternates file\n\n .gitignore                              |   3 +\n Documentation/asciidoc.conf             |   9 +\n Documentation/asciidoctor-extensions.rb |   5 +\n Documentation/config/sendemail.txt      |  56 ++--\n Documentation/git-bugreport.txt         |  55 ++++\n Makefile                                |  27 +-\n bugreport.c                             | 409 ++++++++++++++++++++++++\n builtin/help.c                          |  86 +++++\n compat/compiler.h                       |  24 ++\n generate-bugreport-config-safelist.sh   |  17 +\n generate-cmdlist.sh                     |  19 --\n generate-configlist.sh                  |  24 ++\n help.c                                  | 132 ++------\n help.h                                  |   2 +-\n object-store.h                          |   6 +\n packfile.c                              |   3 +-\n remote-curl.c                           |   8 +\n t/t0091-bugreport.sh                    |  49 +++\n 18 files changed, 778 insertions(+), 156 deletions(-)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100644 compat/compiler.h\n create mode 100755 generate-bugreport-config-safelist.sh\n create mode 100755 generate-configlist.sh\n create mode 100755 t/t0091-bugreport.sh\n\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391219","messageId":"20200206004108.261317-2-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 01/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:40:54Z","receivedAt":"2020-02-06T00:41:27Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\nbuiltin/clean.o, and builtin/config.o. This meant that help.o was\nunusable outside of the context of the main Git executable.\n\nTo make help.o usable by other commands again, move list_config_help()\ninto builtin/help.c (where it makes sense to assume other builtin libraries\nare present).\n\nWhen command-list.h is included but a member is not used, we start to\nhear a compiler warning. Since the config list is generated in a fairly\ndifferent way than the command list, and since commands and config\noptions are semantically different, move the config list into its own\nheader and move the generator into its own script and build rule.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore             |  1 +\n Makefile               | 13 +++++--\n builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n generate-cmdlist.sh    | 19 ----------\n generate-configlist.sh | 24 ++++++++++++\n help.c                 | 85 -----------------------------------------\n help.h                 |  1 -\n 7 files changed, 121 insertions(+), 108 deletions(-)\n create mode 100755 generate-configlist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex aebe7c0908..ea97de83f3 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -189,6 +189,7 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 09f98b777c..5a022367d4 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -814,6 +814,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n@@ -2128,7 +2129,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2148,6 +2149,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2781,7 +2788,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%\n+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n endif\n@@ -2803,7 +2810,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..eca6a00c30\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,24 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\twhile read line\n+\tdo\n+\t\techo \"\t\\\"$line\\\",\"\n+\tdone\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/help.c b/help.c\nindex cf67624a94..a21487db77 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\ndiff --git a/help.h b/help.h\nindex 7a455beeb7..9071894e8c 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391220","messageId":"20200206004108.261317-3-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 02/15] help: add shell-path to --build-options","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:40:55Z","receivedAt":"2020-02-06T00:41:29Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It may be useful to know which shell Git was built to try to point to,\nin the event that shell-based Git commands are failing. $SHELL_PATH is\nset during the build and used to launch the manpage viewer, as well as\nby git-compat-util.h, and it's used during tests. 'git version\n--build-options' is encouraged for use in bug reports, so it makes sense\nto include this information there.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n help.c | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/help.c b/help.c\nindex a21487db77..190722fb0a 100644\n--- a/help.c\n+++ b/help.c\n@@ -654,6 +654,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \t\t\tprintf(\"no commit associated with this build\\n\");\n \t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n \t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\tprintf(\"shell-path: %s\\n\", SHELL_PATH);\n \t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n \t}\n \treturn 0;\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391221","messageId":"20200206004108.261317-4-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:40:56Z","receivedAt":"2020-02-06T00:41:33Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach Git how to prompt the user for a good bug report: reproduction\nsteps, expected behavior, and actual behavior. Later, Git can learn how\nto collect some diagnostic information from the repository.\n\nIf users can send us a well-written bug report which contains diagnostic\ninformation we would otherwise need to ask the user for, we can reduce\nthe number of question-and-answer round trips between the reporter and\nthe Git contributor.\n\nUsers may also wish to send a report like this to their local \"Git\nexpert\" if they have put their repository into a state they are confused\nby.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                      |  1 +\n Documentation/git-bugreport.txt | 41 ++++++++++++++++\n Makefile                        |  5 ++\n bugreport.c                     | 85 +++++++++++++++++++++++++++++++++\n t/t0091-bugreport.sh            | 49 +++++++++++++++++++\n 5 files changed, 181 insertions(+)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ea97de83f3..d89bf9e11e 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -25,6 +25,7 @@\n /git-bisect--helper\n /git-blame\n /git-branch\n+/git-bugreport\n /git-bundle\n /git-cat-file\n /git-check-attr\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..52d49ed7aa\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,41 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+OPTIONS\n+-------\n+-o <path>::\n+--output-directory <path>::\n+\tPlace the resulting bug report file in `<path>` instead of the root of\n+\tthe Git repository.\n+\n+-s <format>::\n+--suffix <format>::\n+\tSpecify an alternate suffix for the bugreport name, to create a file\n+\tnamed 'git-bugreport-<formatted suffix>'. This should take the form of a\n+\tlink:strftime[3] format string; the current local time will be used.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex 5a022367d4..a01a050aa3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -2457,6 +2458,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\ndiff --git a/bugreport.c b/bugreport.c\nnew file mode 100644\nindex 0000000000..db46fb88be\n--- /dev/null\n+++ b/bugreport.c\n@@ -0,0 +1,85 @@\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to share.\\n\");\n+\n+\tstrbuf_addstr(template, template_text);\n+\treturn 0;\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tFILE *report;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\tchar *option_suffix = \"%F-%H%M\";\n+\tstruct stat statbuf;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_STRING('s', \"suffix\", &option_suffix, N_(\"format\"),\n+\t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"\", bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\tif (option_output) {\n+\t\tstrbuf_addstr(&report_path, option_output);\n+\t\tstrbuf_complete(&report_path, '/');\n+\t}\n+\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\tif (!stat(report_path.buf, &statbuf))\n+\t\tdie(\"'%s' already exists\", report_path.buf);\n+\n+\tget_bug_template(&buffer);\n+\n+\treport = fopen_for_writing(report_path.buf);\n+\n+\tif (report == NULL) {\n+\t\tstrbuf_release(&report_path);\n+\t\tdie(\"couldn't open '%s' for writing\", report_path.buf);\n+\t}\n+\n+\tstrbuf_write(&buffer, report);\n+\tfclose(report);\n+\n+\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"), report_path.buf);\n+\n+\tUNLEAK(buffer);\n+\tUNLEAK(report_path);\n+\treturn -launch_editor(report_path.buf, NULL, NULL);\n+}\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..451badff0c\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,49 @@\n+#!/bin/sh\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+check_all_headers_populated() {\n+\twhile read -r line; do\n+\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"; then\n+\t\t\techo \"$line\"\n+\t\t\tread -r nextline\n+\t\t\tif test -z \"$nextline\"; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\tgit bugreport &&\n+\tREPORT=\"$(ls git-bugreport-*)\" &&\n+\tcheck_all_headers_populated <$REPORT &&\n+\trm $REPORT\n+'\n+\n+test_expect_success 'dies if file with same name as report already exists' '\n+\ttouch git-bugreport-duplicate.txt &&\n+\ttest_must_fail git bugreport --suffix duplicate &&\n+\trm git-bugreport-duplicate.txt\n+'\n+\n+test_expect_success '--output-directory puts the report in the provided dir' '\n+\tmkdir foo/ &&\n+\tgit bugreport -o foo/ &&\n+\ttest_path_is_file foo/git-bugreport-* &&\n+\trm -fr foo/\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\tgrep usage output &&\n+\ttest_path_is_missing git-bugreport-*\n+'\n+\n+test_done\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391222","messageId":"20200206004108.261317-5-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 04/15] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:40:57Z","receivedAt":"2020-02-06T00:41:34Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Knowing which version of Git a user has and how it was built allows us\nto more precisely pin down the circumstances when a certain issue\noccurs, so teach bugreport how to tell us the same output as 'git\nversion --build-options'.\n\nIt's not ideal to directly call 'git version --build-options' because\nthat output goes to stdout. Instead, wrap the version string in a helper\nwithin help.[ch] library, and call that helper from within the bugreport\nlibrary.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  4 +++\n bugreport.c                     | 19 ++++++++++++-\n help.c                          | 48 ++++++++++++++++++++-------------\n help.h                          |  1 +\n 4 files changed, 52 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 52d49ed7aa..6ce2ae2eff 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -23,6 +23,10 @@ The following information is requested from the user:\n  - Expected behavior\n  - Actual behavior\n \n+The following information is captured automatically:\n+\n+ - 'git version --build-options'\n+\n OPTIONS\n -------\n -o <path>::\ndiff --git a/bugreport.c b/bugreport.c\nindex db46fb88be..dd21be9d68 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,8 +1,17 @@\n-#include \"builtin.h\"\n+#include \"cache.h\"\n #include \"parse-options.h\"\n #include \"stdio.h\"\n #include \"strbuf.h\"\n #include \"time.h\"\n+#include \"help.h\"\n+\n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, \"git version:\\n\");\n+\tget_version_info(sys_info, 1);\n+\tstrbuf_complete_line(sys_info);\n+}\n \n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n@@ -32,6 +41,11 @@ static int get_bug_template(struct strbuf *template)\n \treturn 0;\n }\n \n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n int cmd_main(int argc, const char **argv)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n@@ -67,6 +81,9 @@ int cmd_main(int argc, const char **argv)\n \n \tget_bug_template(&buffer);\n \n+\tget_header(&buffer, \"System Info\");\n+\tget_system_info(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\ndiff --git a/help.c b/help.c\nindex 190722fb0a..44cee69c11 100644\n--- a/help.c\n+++ b/help.c\n@@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void get_version_info(struct strbuf *buf, int show_build_options)\n+{\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (show_build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addstr(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\tstrbuf_addf(buf, \"shell-path: %s\\n\", SHELL_PATH);\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -637,26 +662,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tget_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n+\n+\tstrbuf_release(&buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\tprintf(\"shell-path: %s\\n\", SHELL_PATH);\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 9071894e8c..500521b908 100644\n--- a/help.h\n+++ b/help.h\n@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void get_version_info(struct strbuf *buf, int show_build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391223","messageId":"20200206004108.261317-6-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 05/15] bugreport: add uname info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:40:58Z","receivedAt":"2020-02-06T00:41:36Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The contents of uname() can give us some insight into what sort of\nsystem the user is running on, and help us replicate their setup if need\nbe. The domainname field is not guaranteed to be available, so don't\ncollect it.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 13 +++++++++++++\n 2 files changed, 14 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 6ce2ae2eff..4dd72c60f5 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -26,6 +26,7 @@ The following information is requested from the user:\n The following information is captured automatically:\n \n  - 'git version --build-options'\n+ - uname sysname, release, version, and machine strings\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex dd21be9d68..4c4b877ea1 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -7,10 +7,23 @@\n \n static void get_system_info(struct strbuf *sys_info)\n {\n+\tstruct utsname uname_info;\n+\n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, \"git version:\\n\");\n \tget_version_info(sys_info, 1);\n \tstrbuf_complete_line(sys_info);\n+\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname -a: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, \"uname() failed with code %d\\n\", errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391224","messageId":"20200206004108.261317-7-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 06/15] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:40:59Z","receivedAt":"2020-02-06T00:41:39Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"To help pinpoint the source of a regression, it is useful to know some\ninfo about the compiler which the user's Git client was built with. By\nadding a generic get_compiler_info() in 'compat/' we can choose which\nrelevant information to share per compiler; to get started, let's\ndemonstrate the version of glibc if the user built with 'gcc'.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     |  5 +++++\n compat/compiler.h               | 24 ++++++++++++++++++++++++\n 3 files changed, 30 insertions(+)\n create mode 100644 compat/compiler.h\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 4dd72c60f5..8bbc4c960c 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -27,6 +27,7 @@ The following information is captured automatically:\n \n  - 'git version --build-options'\n  - uname sysname, release, version, and machine strings\n+ - Compiler-specific info string\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 4c4b877ea1..aaeb94c10c 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"time.h\"\n #include \"help.h\"\n+#include \"compat/compiler.h\"\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -24,6 +25,10 @@ static void get_system_info(struct strbuf *sys_info)\n \t\t\t    uname_info.release,\n \t\t\t    uname_info.version,\n \t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, \"compiler info: \");\n+\tget_compiler_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/compat/compiler.h b/compat/compiler.h\nnew file mode 100644\nindex 0000000000..bda5098e1b\n--- /dev/null\n+++ b/compat/compiler.h\n@@ -0,0 +1,24 @@\n+#ifndef COMPILER_H\n+#define COMPILER_H\n+\n+#include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+\n+#ifdef __GLIBC__\n+#include <gnu/libc-version.h>\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tstrbuf_addf(info, \"glibc: %s\", gnu_get_libc_version());\n+}\n+\n+#else\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tstrbuf_addstr(info, \"get_compiler_info() not implemented\");\n+}\n+\n+#endif\n+\n+#endif /* COMPILER_H */\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391225","messageId":"20200206004108.261317-8-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 07/15] bugreport: add git-remote-https version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:00Z","receivedAt":"2020-02-06T00:41:42Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It's possible for git-remote-curl to be built separately from git; in that\ncase we want to know what version of cURL is used by git-remote-curl, not\nnecessarily which version was present at git-bugreport's build time.\nSo instead, ask git-remote-curl for the version information it knows\nabout.\n\nToday, \"git-remote-http\" and \"git-remote-https\" are aliased to\n\"git-remote-curl\"; but in case we rely on a different library than cURL\nin the future, let's not explicitly reference cURL from bugreport.\n\nFor longevity purposes, invoke the alias \"git-remote-https\" instead of\n\"git-remote-http\".\n\nSince it could have been built at a different time, also report the\nversion and built-from commit of git-remote-curl alongside the cURL info.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 16 ++++++++++++++++\n remote-curl.c                   |  8 ++++++++\n 3 files changed, 25 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 8bbc4c960c..33df4dec7f 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -28,6 +28,7 @@ The following information is captured automatically:\n  - 'git version --build-options'\n  - uname sysname, release, version, and machine strings\n  - Compiler-specific info string\n+ - 'git remote-https --build-info'\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex aaeb94c10c..da5859c131 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -5,6 +5,18 @@\n #include \"time.h\"\n #include \"help.h\"\n #include \"compat/compiler.h\"\n+#include \"run-command.h\"\n+\n+static void get_git_remote_https_version_info(struct strbuf *version_info)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\targv_array_push(&cp.args, \"git\");\n+\targv_array_push(&cp.args, \"remote-https\");\n+\targv_array_push(&cp.args, \"--build-info\");\n+\tif (capture_command(&cp, version_info, 0))\n+\t    strbuf_addstr(version_info, \"'git-remote-https --build-info' not supported\\n\");\n+}\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -29,6 +41,10 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_addstr(sys_info, \"compiler info: \");\n \tget_compiler_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n+\n+\tstrbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n+\tget_git_remote_https_version_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 350d92a074..c590fbfae3 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -17,6 +17,7 @@\n #include \"protocol.h\"\n #include \"quote.h\"\n #include \"transport.h\"\n+#include \"version.h\"\n \n static struct remote *remote;\n /* always ends with a trailing slash */\n@@ -1374,6 +1375,13 @@ int cmd_main(int argc, const char **argv)\n \tstring_list_init(&options.deepen_not, 1);\n \tstring_list_init(&options.push_options, 1);\n \n+\tif (!strcmp(\"--build-info\", argv[1])) {\n+\t\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n+\t\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n+\t\tprintf(\"curl version: %s\\n\", curl_version());\n+\t\treturn 0;\n+\t}\n+\n \t/*\n \t * Just report \"remote-curl\" here (folding all the various aliases\n \t * (\"git-remote-http\", \"git-remote-https\", and etc.) here since they\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391226","messageId":"20200206004108.261317-9-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 08/15] bugreport: include user interactive shell","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:01Z","receivedAt":"2020-02-06T00:41:45Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It's possible a user may complain about the way that Git interacts with\ntheir interactive shell, e.g. autocompletion or shell prompt. In that\ncase, it's useful for us to know which shell they're using\ninteractively.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt | 1 +\n bugreport.c                     | 5 +++++\n 2 files changed, 6 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 33df4dec7f..23265b0d74 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -29,6 +29,7 @@ The following information is captured automatically:\n  - uname sysname, release, version, and machine strings\n  - Compiler-specific info string\n  - 'git remote-https --build-info'\n+ - $SHELL\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex da5859c131..9b51250155 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -21,6 +21,7 @@ static void get_git_remote_https_version_info(struct strbuf *version_info)\n static void get_system_info(struct strbuf *sys_info)\n {\n \tstruct utsname uname_info;\n+\tchar *shell = NULL;\n \n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, \"git version:\\n\");\n@@ -42,6 +43,10 @@ static void get_system_info(struct strbuf *sys_info)\n \tget_compiler_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n \n+\tshell = getenv(\"SHELL\");\n+\tstrbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n+\t\t    shell ? shell : \"<unset>\");\n+\n \tstrbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n \tget_git_remote_https_version_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391227","messageId":"20200206004108.261317-10-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:02Z","receivedAt":"2020-02-06T00:41:46Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Add a new step to the build to generate a safelist of git-config\nvariables which are appropriate to include in the output of\ngit-bugreport. New variables can be added to the safelist by annotating\ntheir documentation in Documentation/config with the \"annotate\" macro,\nwhich is a no-op in AsciiDoc and AsciiDoctor.\n\nSome configs are private in nature, and can contain remote URLs,\npasswords, or other sensitive information. In the event that a user\ndoesn't notice their information while reviewing a bugreport, that user\nmay leak their credentials to other individuals, mailing lists, or bug\ntracking tools inadvertently. Heuristic blocklisting of configuration\nkeys is imperfect and prone to false negatives; given the nature of the\ninformation which can be leaked, a safelist is more reliable.\n\nHowever, it's possible that in some situations, an organization may be\nless concerned with privacy of things like remote URLs and branch names,\nand more concerned with ease of diagnosis for their support staff. In\nthose cases, it may make more sense for that organization to modify the\ncode to use a blocklist. To that end, we should try to mark configs which\nare definitely safe, and configs which are definitely unsafe, and leave\nblank configs which are somewhere in between. To mark a config as safe,\nadd \"annotate:bugreport[include]\" to the corresponding line in the\nconfig documentation; to mark it as unsafe, add\n\"annotate:bugreport[exclude]\" instead.\n\nGenerating bugreport-config-safelist.h at build time by grepping the\ndocumentation for this new macro helps us prevent staleness. The macro\nitself is a no-op and should not alter the appearance of the\ndocumentation in either AsciiDoc or AsciiDoctor, confirmable by running:\n\n  cd Documentation\n  ./doc-diff --asciidoctor HEAD^ HEAD\n  ./doc-diff --asciidoc HEAD^ HEAD\n\nDiffing the rendered HTML shows that only inline comments were added,\nwhich shouldn't be a problem.\n\nAdditionally, add annotations to the sendemail config documentation in\norder to demonstrate a proof of concept.\n\nHelped-by: Martin Ågren <martin.agren@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                              |  1 +\n Documentation/asciidoc.conf             |  9 ++++\n Documentation/asciidoctor-extensions.rb |  5 +++\n Documentation/config/sendemail.txt      | 56 ++++++++++++-------------\n Makefile                                |  7 ++++\n generate-bugreport-config-safelist.sh   | 17 ++++++++\n 6 files changed, 67 insertions(+), 28 deletions(-)\n create mode 100755 generate-bugreport-config-safelist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex d89bf9e11e..bd2f49b996 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -192,6 +192,7 @@\n /gitweb/static/gitweb.min.*\n /config-list.h\n /command-list.h\n+/bugreport-config-safelist.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\nindex 8fc4b67081..663e06481f 100644\n--- a/Documentation/asciidoc.conf\n+++ b/Documentation/asciidoc.conf\n@@ -6,9 +6,14 @@\n #\n # Show Git link as: <command>(<section>); if section is defined, else just show\n # the command.\n+#\n+# The annotate macro does nothing as far as rendering is\n+# concerned -- we just grep for it in the sources to populate\n+# things like the bugreport safelist.\n \n [macros]\n (?su)[\\\\]?(?P<name>linkgit):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n+(?su)[\\\\]?(?P<name>annotate):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n \n [attributes]\n asterisk=&#42;\n@@ -28,6 +33,8 @@ ifdef::backend-docbook[]\n {0#<citerefentry>}\n {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n {0#</citerefentry>}\n+[annotate-inlinemacro]\n+{0#}\n endif::backend-docbook[]\n \n ifdef::backend-docbook[]\n@@ -94,4 +101,6 @@ ifdef::backend-xhtml11[]\n git-relative-html-prefix=\n [linkgit-inlinemacro]\n <a href=\"{git-relative-html-prefix}{target}.html\">{target}{0?({0})}</a>\n+[annotate-inlinemacro]\n+<!-- -->\n endif::backend-xhtml11[]\ndiff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\nindex d906a00803..382bd8f6f4 100644\n--- a/Documentation/asciidoctor-extensions.rb\n+++ b/Documentation/asciidoctor-extensions.rb\n@@ -37,6 +37,10 @@ module Git\n           output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n         end\n         output\n+\n+    class AnnotateProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n+      def process(parent, target, attrs)\n+        \"\"\n       end\n     end\n   end\n@@ -45,4 +49,5 @@ end\n Asciidoctor::Extensions.register do\n   inline_macro Git::Documentation::LinkGitProcessor, :linkgit\n   postprocessor Git::Documentation::DocumentPostProcessor\n+  inline_macro Git::Documentation::AnnotateProcessor, :annotate\n end\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 0006faf800..fe27473e44 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -4,7 +4,7 @@ sendemail.identity::\n \tvalues in the 'sendemail' section. The default identity is\n \tthe value of `sendemail.identity`.\n \n-sendemail.smtpEncryption::\n+sendemail.smtpEncryption annotate:bugreport[include] ::\n \tSee linkgit:git-send-email[1] for description.  Note that this\n \tsetting is not subject to the 'identity' mechanism.\n \n@@ -15,7 +15,7 @@ sendemail.smtpsslcertpath::\n \tPath to ca-certificates (either a directory or a single file).\n \tSet it to an empty string to disable certificate verification.\n \n-sendemail.<identity>.*::\n+sendemail.<identity>.* annotate:bugreport[exclude] ::\n \tIdentity-specific versions of the 'sendemail.*' parameters\n \tfound below, taking precedence over those when this\n \tidentity is selected, through either the command-line or\n@@ -23,41 +23,41 @@ sendemail.<identity>.*::\n \n sendemail.aliasesFile::\n sendemail.aliasFileType::\n-sendemail.annotate::\n-sendemail.bcc::\n-sendemail.cc::\n-sendemail.ccCmd::\n-sendemail.chainReplyTo::\n-sendemail.confirm::\n-sendemail.envelopeSender::\n-sendemail.from::\n-sendemail.multiEdit::\n-sendemail.signedoffbycc::\n-sendemail.smtpPass::\n-sendemail.suppresscc::\n-sendemail.suppressFrom::\n-sendemail.to::\n-sendemail.tocmd::\n-sendemail.smtpDomain::\n-sendemail.smtpServer::\n-sendemail.smtpServerPort::\n-sendemail.smtpServerOption::\n-sendemail.smtpUser::\n-sendemail.thread::\n-sendemail.transferEncoding::\n-sendemail.validate::\n-sendemail.xmailer::\n+sendemail.annotate annotate:bugreport[include] ::\n+sendemail.bcc annotate:bugreport[include] ::\n+sendemail.cc annotate:bugreport[include] ::\n+sendemail.ccCmd annotate:bugreport[include] ::\n+sendemail.chainReplyTo annotate:bugreport[include] ::\n+sendemail.confirm annotate:bugreport[include] ::\n+sendemail.envelopeSender annotate:bugreport[include] ::\n+sendemail.from annotate:bugreport[include] ::\n+sendemail.multiEdit annotate:bugreport[include] ::\n+sendemail.signedoffbycc annotate:bugreport[include] ::\n+sendemail.smtpPass annotate:bugreport[exclude] ::\n+sendemail.suppresscc annotate:bugreport[include] ::\n+sendemail.suppressFrom annotate:bugreport[include] ::\n+sendemail.to annotate:bugreport[include] ::\n+sendemail.tocmd annotate:bugreport[include] ::\n+sendemail.smtpDomain annotate:bugreport[include] ::\n+sendemail.smtpServer annotate:bugreport[include] ::\n+sendemail.smtpServerPort annotate:bugreport[include] ::\n+sendemail.smtpServerOption annotate:bugreport[include] ::\n+sendemail.smtpUser annotate:bugreport[exclude] ::\n+sendemail.thread annotate:bugreport[include] ::\n+sendemail.transferEncoding annotate:bugreport[include] ::\n+sendemail.validate annotate:bugreport[include] ::\n+sendemail.xmailer annotate:bugreport[include] ::\n \tSee linkgit:git-send-email[1] for description.\n \n sendemail.signedoffcc (deprecated)::\n \tDeprecated alias for `sendemail.signedoffbycc`.\n \n-sendemail.smtpBatchSize::\n+sendemail.smtpBatchSize annotate:bugreport[include] ::\n \tNumber of messages to be sent per connection, after that a relogin\n \twill happen.  If the value is 0 or undefined, send all messages in\n \tone connection.\n \tSee also the `--batch-size` option of linkgit:git-send-email[1].\n \n-sendemail.smtpReloginDelay::\n+sendemail.smtpReloginDelay annotate:bugreport[include] ::\n \tSeconds wait before reconnecting to smtp server.\n \tSee also the `--relogin-delay` option of linkgit:git-send-email[1].\ndiff --git a/Makefile b/Makefile\nindex a01a050aa3..2bc9f112ea 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n \n GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n+GENERATED_H += bugreport-config-safelist.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n \t$(FIND) . \\\n@@ -2163,6 +2164,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\tcommand-list.txt >$@+ && mv $@+ $@\n \n+bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n+\n+bugreport-config-safelist.h: Documentation/config/*.txt\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\ndiff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\nnew file mode 100755\nindex 0000000000..17d92a91c5\n--- /dev/null\n+++ b/generate-bugreport-config-safelist.sh\n@@ -0,0 +1,17 @@\n+#!/bin/sh\n+\n+cat <<EOF\n+/* Automatically generated by bugreport-generate-config-safelist.sh */\n+\n+\n+static const char *bugreport_config_safelist[] = {\n+EOF\n+\n+# cat all regular files in Documentation/config\n+find Documentation/config -type f -exec cat {} \\; |\n+# print the command name which matches the annotate-bugreport macro\n+sed -n 's/^\\(.*\\) \\+annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' | sort\n+\n+cat <<EOF\n+};\n+EOF\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391228","messageId":"20200206004108.261317-11-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:03Z","receivedAt":"2020-02-06T00:41:48Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach bugreport to gather the values of config options which are present\nin 'bugreport-config-safelist.h', and show their origin scope.\n\nMany config options are sensitive, and many Git add-ons use config\noptions which git-core does not know about; it is better only to gather\nconfig options which we know to be safe, rather than excluding options\nwhich we know to be unsafe.\n\nRather than including the path to someone's config, which can reveal\nfilesystem layout and project names, just name the scope (e.g. system,\nglobal, local) of the config source.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n Makefile                        |  2 ++\n bugreport.c                     | 34 +++++++++++++++++++++++++++++++++\n 3 files changed, 37 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 23265b0d74..4e9171d1bd 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -30,6 +30,7 @@ The following information is captured automatically:\n  - Compiler-specific info string\n  - 'git remote-https --build-info'\n  - $SHELL\n+ - Selected config values\n \n OPTIONS\n -------\ndiff --git a/Makefile b/Makefile\nindex 2bc9f112ea..7b139230ae 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2131,6 +2131,8 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n+bugreport.sp bugreport.s bugreport.o: bugreport-config-safelist.h\n+\n builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\ndiff --git a/bugreport.c b/bugreport.c\nindex 9b51250155..16216bff8e 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -6,6 +6,9 @@\n #include \"help.h\"\n #include \"compat/compiler.h\"\n #include \"run-command.h\"\n+#include \"config.h\"\n+#include \"bugreport-config-safelist.h\"\n+#include \"khash.h\"\n \n static void get_git_remote_https_version_info(struct strbuf *version_info)\n {\n@@ -52,6 +55,29 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_complete_line(sys_info);\n }\n \n+static void get_safelisted_config(struct strbuf *config_info)\n+{\n+\tsize_t idx;\n+\tstruct string_list_item *it = NULL;\n+\tstruct key_value_info *kv_info = NULL;\n+\n+\tfor (idx = 0; idx < ARRAY_SIZE(bugreport_config_safelist); idx++) {\n+\t\tconst struct string_list *list =\n+\t\t\tgit_config_get_value_multi(bugreport_config_safelist[idx]);\n+\n+\t\tif (!list)\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_addf(config_info, \"%s:\\n\", bugreport_config_safelist[idx]);\n+\t\tfor_each_string_list_item(it, list) {\n+\t\t\tkv_info = it->util;\n+\t\t\tstrbuf_addf(config_info, \"  %s (%s)\\n\", it->string,\n+\t\t\t\t    kv_info ? config_scope_name(kv_info->scope)\n+\t\t\t\t\t    : \"source unknown\");\n+\t\t}\n+\t}\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -94,6 +120,7 @@ int cmd_main(int argc, const char **argv)\n \tchar *option_output = NULL;\n \tchar *option_suffix = \"%F-%H%M\";\n \tstruct stat statbuf;\n+\tint nongit_ok = 0;\n \n \tconst struct option bugreport_options[] = {\n \t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n@@ -102,6 +129,10 @@ int cmd_main(int argc, const char **argv)\n \t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n \t\tOPT_END()\n \t};\n+\n+\t/* Prerequisite for hooks and config checks */\n+\tsetup_git_directory_gently(&nongit_ok);\n+\n \targc = parse_options(argc, argv, \"\", bugreport_options,\n \t\t\t     bugreport_usage, 0);\n \n@@ -123,6 +154,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"System Info\");\n \tget_system_info(&buffer);\n \n+\tget_header(&buffer, \"Safelisted Config Info\");\n+\tget_safelisted_config(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391229","messageId":"20200206004108.261317-12-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 11/15] bugreport: collect list of populated hooks","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:04Z","receivedAt":"2020-02-06T00:41:51Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Occasionally a failure a user is seeing may be related to a specific\nhook which is being run, perhaps without the user realizing. While the\ncontents of hooks can be sensitive - containing user data or process\ninformation specific to the user's organization - simply knowing that a\nhook is being run at a certain stage can help us to understand whether\nsomething is going wrong.\n\nWithout a definitive list of hook names within the code, we compile our\nown list from the documentation. This is likely prone to bitrot. To\nreduce the amount of code humans need to read, we turn the list into a\nstring_list and iterate over it (as we are calling the same find_hook\noperation on each string). However, since bugreport should primarily be\ncalled by the user, the performance loss from massaging the string\nseems acceptable.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 53 +++++++++++++++++++++++++++++++++\n 2 files changed, 54 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 4e9171d1bd..779c9c7fd9 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -31,6 +31,7 @@ The following information is captured automatically:\n  - 'git remote-https --build-info'\n  - $SHELL\n  - Selected config values\n+ - A list of enabled hooks\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 16216bff8e..3b0a2b12cc 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -9,6 +9,7 @@\n #include \"config.h\"\n #include \"bugreport-config-safelist.h\"\n #include \"khash.h\"\n+#include \"run-command.h\"\n \n static void get_git_remote_https_version_info(struct strbuf *version_info)\n {\n@@ -78,6 +79,55 @@ static void get_safelisted_config(struct strbuf *config_info)\n \t}\n }\n \n+static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n+{\n+\t/*\n+\t * Doesn't look like there is a list of all possible hooks; so below is\n+\t * a transcription of `git help hooks`.\n+\t */\n+\tconst char *hooks = \"applypatch-msg,\"\n+\t\t\t    \"pre-applypatch,\"\n+\t\t\t    \"post-applypatch,\"\n+\t\t\t    \"pre-commit,\"\n+\t\t\t    \"pre-merge-commit,\"\n+\t\t\t    \"prepare-commit-msg,\"\n+\t\t\t    \"commit-msg,\"\n+\t\t\t    \"post-commit,\"\n+\t\t\t    \"pre-rebase,\"\n+\t\t\t    \"post-checkout,\"\n+\t\t\t    \"post-merge,\"\n+\t\t\t    \"pre-push,\"\n+\t\t\t    \"pre-receive,\"\n+\t\t\t    \"update,\"\n+\t\t\t    \"post-receive,\"\n+\t\t\t    \"post-update,\"\n+\t\t\t    \"push-to-checkout,\"\n+\t\t\t    \"pre-auto-gc,\"\n+\t\t\t    \"post-rewrite,\"\n+\t\t\t    \"sendemail-validate,\"\n+\t\t\t    \"fsmonitor-watchman,\"\n+\t\t\t    \"p4-pre-submit,\"\n+\t\t\t    \"post-index-changex\";\n+\tstruct string_list hooks_list = STRING_LIST_INIT_DUP;\n+\tstruct string_list_item *iter = NULL;\n+\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(hook_info,\n+\t\t\t\"not run from a git repository - no hooks to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstring_list_split(&hooks_list, hooks, ',', -1);\n+\n+\tfor_each_string_list_item(iter, &hooks_list) {\n+\t\tif (find_hook(iter->string)) {\n+\t\t\tstrbuf_addstr(hook_info, iter->string);\n+\t\t\tstrbuf_complete_line(hook_info);\n+\t\t}\n+\t}\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -157,6 +207,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Safelisted Config Info\");\n \tget_safelisted_config(&buffer);\n \n+\tget_header(&buffer, \"Enabled Hooks\");\n+\tget_populated_hooks(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391230","messageId":"20200206004108.261317-13-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 12/15] bugreport: count loose objects","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:05Z","receivedAt":"2020-02-06T00:41:54Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The number of unpacked objects in a user's repository may help us\nunderstand the root of the problem they're seeing, especially if a\ncommand is running unusually slowly.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 52 +++++++++++++++++++++++++++++++++\n 2 files changed, 53 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 779c9c7fd9..7e1ed44cb4 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -32,6 +32,7 @@ The following information is captured automatically:\n  - $SHELL\n  - Selected config values\n  - A list of enabled hooks\n+ - The number of loose objects in the repository\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 3b0a2b12cc..9552e2922e 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -10,6 +10,7 @@\n #include \"bugreport-config-safelist.h\"\n #include \"khash.h\"\n #include \"run-command.h\"\n+#include \"object-store.h\"\n \n static void get_git_remote_https_version_info(struct strbuf *version_info)\n {\n@@ -128,6 +129,54 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n \t}\n }\n \n+static int loose_object_cb(const struct object_id *oid, const char *path,\n+\t\t\t   void *data) {\n+\tint *loose_object_count = data;\n+\n+\tif (loose_object_count) {\n+\t\t(*loose_object_count)++;\n+\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {\n+\n+\tint local_loose_object_count = 0, total_loose_object_count = 0;\n+\tint local_count_questionable = 0, total_count_questionable = 0;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(obj_info,\n+\t\t\t\"not run from a git repository - no objects to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tlocal_count_questionable = for_each_loose_object(\n+\t\t\t\t\tloose_object_cb,\n+\t\t\t\t\t&local_loose_object_count,\n+\t\t\t\t\tFOR_EACH_OBJECT_LOCAL_ONLY);\n+\n+\ttotal_count_questionable = for_each_loose_object(\n+\t\t\t\t\tloose_object_cb,\n+\t\t\t\t\t&total_loose_object_count,\n+\t\t\t\t\t0);\n+\n+\tstrbuf_addf(obj_info, \"%d local loose objects%s\\n\",\n+\t\t    local_loose_object_count,\n+\t\t    local_count_questionable ? \" (problem during count)\" : \"\");\n+\n+\tstrbuf_addf(obj_info, \"%d alternate loose objects%s\\n\",\n+\t\t    total_loose_object_count - local_loose_object_count,\n+\t\t    (local_count_questionable || total_count_questionable)\n+\t\t\t? \" (problem during count)\"\n+\t\t\t: \"\");\n+\n+\tstrbuf_addf(obj_info, \"%d total loose objects%s\\n\",\n+\t\t    total_loose_object_count,\n+\t\t    total_count_questionable ? \" (problem during count)\" : \"\");\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -210,6 +259,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Enabled Hooks\");\n \tget_populated_hooks(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Loose Object Counts\");\n+\tget_loose_object_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391231","messageId":"20200206004108.261317-14-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 13/15] bugreport: add packed object summary","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:06Z","receivedAt":"2020-02-06T00:41:56Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Alongside the loose object counts, it can be useful to show the number\nof packs and packed objects. This way we can check whether the repo has\nan appropriate ratio of packed to loose objects to help determine\nwhether it's behaving correctly.\n\nAdd a utility to easily traverse all packfiles in a given repository.\nUse it in packfile.c and remove a redundant call to\nprepare_packed_git(), which is already called in get_all_packs().\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\nPerhaps the macro should be in another patch? I didn't spend a lot of\ntime looking for anybody who could conceivably be iterating packs; if I\nwere to do so, I'd break this change out separately.\n\nI considered following the pattern in the rest of the file, where the\nforeach takes a callback and data pointer, but found it would be\ncumbersome to use with for_each_packed_object() - I'd have to add a new\ncallback just to handle the pack, and bundle that function's callback\ndata along with the callback pointer. It seemed like overkill.\n\n - Emily\n\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 30 ++++++++++++++++++++++++++++++\n object-store.h                  |  6 ++++++\n packfile.c                      |  3 +--\n 4 files changed, 38 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 7e1ed44cb4..309b34fc42 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -33,6 +33,7 @@ The following information is captured automatically:\n  - Selected config values\n  - A list of enabled hooks\n  - The number of loose objects in the repository\n+ - The number of packs and packed objects in the repository\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 9552e2922e..d554488f3e 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -177,6 +177,33 @@ static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {\n \t\t    total_count_questionable ? \" (problem during count)\" : \"\");\n }\n \n+static void get_packed_object_summary(struct strbuf *obj_info, int nongit)\n+{\n+\tstruct packed_git *pack = NULL;\n+\tint pack_count = 0;\n+\tint object_count = 0;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(obj_info,\n+\t\t\t\"not run from a git repository - no objects to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tfor_each_pack(the_repository, pack) {\n+\t\tpack_count++;\n+\t\t/*\n+\t\t * To accurately count how many objects are packed, look inside\n+\t\t * the packfile's index.\n+\t\t */\n+\t\topen_pack_index(pack);\n+\t\tobject_count += pack->num_objects;\n+\t}\n+\n+\tstrbuf_addf(obj_info, \"%d total packs (%d objects)\\n\", pack_count,\n+\t\t    object_count);\n+\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -262,6 +289,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Loose Object Counts\");\n \tget_loose_object_summary(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Packed Object Summary\");\n+\tget_packed_object_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\ndiff --git a/object-store.h b/object-store.h\nindex 55ee639350..518c73469d 100644\n--- a/object-store.h\n+++ b/object-store.h\n@@ -6,6 +6,7 @@\n #include \"list.h\"\n #include \"sha1-array.h\"\n #include \"strbuf.h\"\n+#include \"packfile.h\"\n \n struct object_directory {\n \tstruct object_directory *next;\n@@ -403,4 +404,9 @@ int for_each_object_in_pack(struct packed_git *p,\n int for_each_packed_object(each_packed_object_fn, void *,\n \t\t\t   enum for_each_object_flags flags);\n \n+#define for_each_pack(repo, pack) \t\t\\\n+\t\tfor (pack = get_all_packs(repo);\\\n+\t\t     pack;\t\t\t\\\n+\t\t     pack = pack->next)\n+\n #endif /* OBJECT_STORE_H */\ndiff --git a/packfile.c b/packfile.c\nindex 7e7c04e4d8..6873827fb5 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -2061,8 +2061,7 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,\n \tint r = 0;\n \tint pack_errors = 0;\n \n-\tprepare_packed_git(the_repository);\n-\tfor (p = get_all_packs(the_repository); p; p = p->next) {\n+\tfor_each_pack(the_repository, p) {\n \t\tif ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)\n \t\t\tcontinue;\n \t\tif ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391232","messageId":"20200206004108.261317-15-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 14/15] bugreport: list contents of $OBJDIR/info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:07Z","receivedAt":"2020-02-06T00:41:59Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Miscellaneous information used about the object store can end up in\n.git/objects/info; this can help us understand what may be going on with\nthe object store when the user is reporting a bug. Otherwise, it could\nbe difficult to track down what is going wrong with an object which\nisn't kept locally to .git/objects/ or .git/objects/pack. Having some\nunderstanding of where the user's objects may be kept can save us some\nhops during the bug reporting process.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 54 +++++++++++++++++++++++++++++++++\n 2 files changed, 55 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 309b34fc42..a21d081616 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -34,6 +34,7 @@ The following information is captured automatically:\n  - A list of enabled hooks\n  - The number of loose objects in the repository\n  - The number of packs and packed objects in the repository\n+ - A list of the contents of .git/objects/info (or equivalent)\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex d554488f3e..3a3d33f680 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -204,6 +204,57 @@ static void get_packed_object_summary(struct strbuf *obj_info, int nongit)\n \n }\n \n+static void list_contents_of_dir_recursively(struct strbuf *contents,\n+\t\t\t\t      \t     struct strbuf *dirpath)\n+{\n+\tstruct dirent *d;\n+\tDIR *dir;\n+\tsize_t path_len;\n+\n+\tdir = opendir(dirpath->buf);\n+\tif (!dir)\n+\t\treturn;\n+\n+\tstrbuf_complete(dirpath, '/');\n+\tpath_len = dirpath->len;\n+\n+\twhile ((d = readdir(dir))) {\n+\t\tif (!strcmp(d->d_name, \".\") || !strcmp(d->d_name, \"..\"))\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_addbuf(contents, dirpath);\n+\t\tstrbuf_addstr(contents, d->d_name);\n+\t\tstrbuf_complete_line(contents);\n+\n+\t\tif (d->d_type == DT_DIR) {\n+\t\t\tstrbuf_addstr(dirpath, d->d_name);\n+\t\t\tlist_contents_of_dir_recursively(contents, dirpath);\n+\t\t}\n+\t\tstrbuf_setlen(dirpath, path_len);\n+\t}\n+\n+\tclosedir(dir);\n+}\n+\n+static void get_object_info_summary(struct strbuf *obj_info, int nongit)\n+{\n+\tstruct strbuf dirpath = STRBUF_INIT;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(obj_info,\n+\t\t\t\"not run from a git repository - object info unavailable\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstrbuf_addstr(&dirpath, get_object_directory());\n+\tstrbuf_complete(&dirpath, '/');\n+\tstrbuf_addstr(&dirpath, \"info/\");\n+\n+\tlist_contents_of_dir_recursively(obj_info, &dirpath);\n+\n+\tstrbuf_release(&dirpath);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -292,6 +343,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Packed Object Summary\");\n \tget_packed_object_summary(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Object Info Summary\");\n+\tget_object_info_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391233","messageId":"20200206004108.261317-16-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v6 15/15] bugreport: summarize contents of alternates file","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-06T00:41:08Z","receivedAt":"2020-02-06T00:42:02Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"In some cases, it could be that the user is having a problem with an\nobject which isn't present in their normal object directory. We can get\na hint that that might be the case by examining the list of alternates\nwhere their object may be stored instead. Since paths to alternates may\nbe sensitive, we'll instead count how many alternates have been\nspecified and note how many of them exist or are broken.\n\nWhile object-cache.h describes a function \"foreach_alt_odb()\", this\nfunction does not provide information on broken alternates, which are\nskipped over in \"link_alt_odb_entry()\". Since the goal is to identify\nmissing alternates, we can gather the contents of\n.git/objects/info/alternates manually.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 45 +++++++++++++++++++++++++++++++++\n 2 files changed, 46 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex a21d081616..e870900c80 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -35,6 +35,7 @@ The following information is captured automatically:\n  - The number of loose objects in the repository\n  - The number of packs and packed objects in the repository\n  - A list of the contents of .git/objects/info (or equivalent)\n+ - The number of valid and invalid alternates\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 3a3d33f680..9d4d5c8e6f 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -255,6 +255,48 @@ static void get_object_info_summary(struct strbuf *obj_info, int nongit)\n \tstrbuf_release(&dirpath);\n }\n \n+static void get_alternates_summary(struct strbuf *alternates_info, int nongit)\n+{\n+\tstruct strbuf alternates_path = STRBUF_INIT;\n+\tstruct strbuf alternate = STRBUF_INIT;\n+\tFILE *file;\n+\tsize_t exists = 0, broken = 0;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(alternates_info,\n+\t\t\t\"not run from a git repository - alternates unavailable\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstrbuf_addstr(&alternates_path, get_object_directory());\n+\tstrbuf_complete(&alternates_path, '/');\n+\tstrbuf_addstr(&alternates_path, \"info/alternates\");\n+\n+\tfile = fopen(alternates_path.buf, \"r\");\n+\tif (!file) {\n+\t\tstrbuf_addstr(alternates_info, \"No alternates file found.\\n\");\n+\t\tstrbuf_release(&alternates_path);\n+\t\treturn;\n+\t}\n+\n+\twhile (strbuf_getline(&alternate, file) != EOF) {\n+\t\tif (!access(alternate.buf, F_OK))\n+\t\t\texists++;\n+\t\telse\n+\t\t\tbroken++;\n+\t}\n+\n+\tstrbuf_addf(alternates_info,\n+\t\t    \"%zd alternates found (%zd working, %zd broken)\\n\",\n+\t\t    exists + broken,\n+\t\t    exists,\n+\t\t    broken);\n+\n+\tfclose(file);\n+\tstrbuf_release(&alternate);\n+\tstrbuf_release(&alternates_path);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -346,6 +388,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Object Info Summary\");\n \tget_object_info_summary(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Alternates\");\n+\tget_alternates_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.341.g760bfbb309-goog\n\n"},{"id":"391236","messageId":"20200206013533.GA3993@danh.dev","threadId":"52442","inReplyTo":"20200206004108.261317-2-emilyshaffer@google.com","subject":"Re: [PATCH v6 01/15] help: move list_config_help to builtin/help","fromName":"Danh Doan","fromEmail":"congdanhqx@gmail.com","sentAt":"2020-02-06T01:35:33Z","receivedAt":"2020-02-06T01:35:38Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2020-02-05 16:40:54-0800, Emily Shaffer <emilyshaffer@google.com> wrote:\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> index 71158f7d8b..45fecf8bdf 100755\n> --- a/generate-cmdlist.sh\n> +++ b/generate-cmdlist.sh\n> @@ -76,23 +76,6 @@ print_command_list () {\n>  \techo \"};\"\n>  }\n>  \n> -print_config_list () {\n> -\tcat <<EOF\n> -static const char *config_name_list[] = {\n> -EOF\n> -\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> -\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> -\tsort |\n> -\twhile read line\n> -\tdo\n> -\t\techo \"\t\\\"$line\\\",\"\n> -\tdone\n> -\tcat <<EOF\n> -\tNULL,\n> -};\n> -EOF\n> -}\n> -\n>  exclude_programs=\n>  while test \"--exclude-program\" = \"$1\"\n>  do\n> @@ -113,5 +96,3 @@ echo\n>  define_category_names \"$1\"\n>  echo\n>  print_command_list \"$1\"\n> -echo\n> -print_config_list\n> diff --git a/generate-configlist.sh b/generate-configlist.sh\n> new file mode 100755\n> index 0000000000..eca6a00c30\n> --- /dev/null\n> +++ b/generate-configlist.sh\n> @@ -0,0 +1,24 @@\n> +#!/bin/sh\n> +\n> +echo \"/* Automatically generated by generate-configlist.sh */\"\n> +echo\n> +\n> +print_config_list () {\n> +\tcat <<EOF\n> +static const char *config_name_list[] = {\n> +EOF\n> +\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> +\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> +\tsort |\n> +\twhile read line\n> +\tdo\n> +\t\techo \"\t\\\"$line\\\",\"\n> +\tdone\n\nThis while-read-echo was moved from generate-cmdlist.sh,\nwhich has some logic to work with read-variable.\n\nWe're moving it out, I think apply this diff on top of it will make the code easier to read.\n\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nindex eca6a00c30..163dbf30bb 100755\n--- a/generate-configlist.sh\n+++ b/generate-configlist.sh\n@@ -10,10 +10,7 @@ EOF\n \tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n \tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n \tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n+\tsed 's/^/\t\"/; s/$/\",/'\n \tcat <<EOF\n \tNULL,\n };\n\n\n\n-- \nDanh\n"},{"id":"391326","messageId":"20200207141802.GE2868@szeder.dev","threadId":"52442","inReplyTo":"20200206004108.261317-4-emilyshaffer@google.com","subject":"Re: [PATCH v6 03/15] bugreport: add tool to generate debugging info","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2020-02-07T14:18:02Z","receivedAt":"2020-02-07T14:18:09Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, Feb 05, 2020 at 04:40:56PM -0800, Emily Shaffer wrote:\n> diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\n> new file mode 100755\n> index 0000000000..451badff0c\n> --- /dev/null\n> +++ b/t/t0091-bugreport.sh\n> @@ -0,0 +1,49 @@\n> +#!/bin/sh\n> +\n> +test_description='git bugreport'\n> +\n> +. ./test-lib.sh\n> +\n> +# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n> +# information there; we can make sure all our headers were followed by some\n> +# information to check if the command was successful.\n> +HEADER_PATTERN=\"^\\[.*\\]$\"\n> +check_all_headers_populated() {\n> +\twhile read -r line; do\n> +\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"; then\n> +\t\t\techo \"$line\"\n> +\t\t\tread -r nextline\n> +\t\t\tif test -z \"$nextline\"; then\n> +\t\t\t\treturn 1;\n> +\t\t\tfi\n> +\t\tfi\n> +\tdone\n> +}\n> +\n> +test_expect_success 'creates a report with content in the right places' '\n> +\tgit bugreport &&\n> +\tREPORT=\"$(ls git-bugreport-*)\" &&\n\nWhat if the globbing were to match more than one file?\n\n> +\tcheck_all_headers_populated <$REPORT &&\n> +\trm $REPORT\n\nPlease register a cleanup commands like this with 'test_when_finished'.\n\n> +'\n> +\n> +test_expect_success 'dies if file with same name as report already exists' '\n> +\ttouch git-bugreport-duplicate.txt &&\n> +\ttest_must_fail git bugreport --suffix duplicate &&\n> +\trm git-bugreport-duplicate.txt\n> +'\n> +\n> +test_expect_success '--output-directory puts the report in the provided dir' '\n> +\tmkdir foo/ &&\n\nIs it really necessary to create the directory in advance?  Or to put\nit in another way: shouldn't 'git bugreport' create any missing\nleading directories of the path given for its '-o' option?  FWIW, 'git\nformat-patch -o dir ...' does create all necessary directories.\n\n> +\tgit bugreport -o foo/ &&\n> +\ttest_path_is_file foo/git-bugreport-* &&\n\nWhat if the globbing were to match more than one file? :)\n\n> +\trm -fr foo/\n> +'\n> +\n> +test_expect_success 'incorrect arguments abort with usage' '\n> +\ttest_must_fail git bugreport --false 2>output &&\n> +\tgrep usage output &&\n\nThis breaks the GETTEXT_POISON CI job, because \"usage\" is translated,\nso the test should not look for it with plain 'grep'.  Please use\n'test_i18ngrep' instead.\n\n> +\ttest_path_is_missing git-bugreport-*\n> +'\n> +\n> +test_done\n> -- \n> 2.25.0.341.g760bfbb309-goog\n> \n"},{"id":"391327","messageId":"20200207144725.GF2868@szeder.dev","threadId":"52442","inReplyTo":"20200206004108.261317-11-emilyshaffer@google.com","subject":"Re: [PATCH v6 10/15] bugreport: add config values from safelist","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2020-02-07T14:47:25Z","receivedAt":"2020-02-07T14:47:32Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, Feb 05, 2020 at 04:41:03PM -0800, Emily Shaffer wrote:\n> +static void get_safelisted_config(struct strbuf *config_info)\n> +{\n> +\tsize_t idx;\n> +\tstruct string_list_item *it = NULL;\n> +\tstruct key_value_info *kv_info = NULL;\n> +\n> +\tfor (idx = 0; idx < ARRAY_SIZE(bugreport_config_safelist); idx++) {\n\nGCC 9 complains about this loop condition:\n\n      CC bugreport.o\n  \n  bugreport.c: In function 'get_safelisted_config':\n  \n  bugreport.c:66:20: error: comparison of unsigned expression < 0 is always false [-Werror=type-limits]\n  \n     66 |  for (idx = 0; idx < ARRAY_SIZE(bugreport_config_safelist); idx++) {\n  \n        |                    ^\n\nI don't understand this error, that autogenerated\n'bugreport_config_safelist' array clearly has a a non-zero size.\nWhat am I missing?\n\n\n> +\t\tconst struct string_list *list =\n> +\t\t\tgit_config_get_value_multi(bugreport_config_safelist[idx]);\n> +\n> +\t\tif (!list)\n> +\t\t\tcontinue;\n> +\n> +\t\tstrbuf_addf(config_info, \"%s:\\n\", bugreport_config_safelist[idx]);\n> +\t\tfor_each_string_list_item(it, list) {\n> +\t\t\tkv_info = it->util;\n> +\t\t\tstrbuf_addf(config_info, \"  %s (%s)\\n\", it->string,\n> +\t\t\t\t    kv_info ? config_scope_name(kv_info->scope)\n> +\t\t\t\t\t    : \"source unknown\");\n> +\t\t}\n> +\t}\n> +}\n> +\n"},{"id":"391328","messageId":"20200207145409.GG2868@szeder.dev","threadId":"52442","inReplyTo":"20200206004108.261317-4-emilyshaffer@google.com","subject":"Re: [PATCH v6 03/15] bugreport: add tool to generate debugging info","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2020-02-07T14:54:09Z","receivedAt":"2020-02-07T14:54:16Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, Feb 05, 2020 at 04:40:56PM -0800, Emily Shaffer wrote:\n> Teach Git how to prompt the user for a good bug report: reproduction\n> steps, expected behavior, and actual behavior. Later, Git can learn how\n> to collect some diagnostic information from the repository.\n> \n> If users can send us a well-written bug report which contains diagnostic\n> information we would otherwise need to ask the user for, we can reduce\n> the number of question-and-answer round trips between the reporter and\n> the Git contributor.\n> \n> Users may also wish to send a report like this to their local \"Git\n> expert\" if they have put their repository into a state they are confused\n> by.\n> \n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  .gitignore                      |  1 +\n>  Documentation/git-bugreport.txt | 41 ++++++++++++++++\n>  Makefile                        |  5 ++\n>  bugreport.c                     | 85 +++++++++++++++++++++++++++++++++\n>  t/t0091-bugreport.sh            | 49 +++++++++++++++++++\n>  5 files changed, 181 insertions(+)\n>  create mode 100644 Documentation/git-bugreport.txt\n>  create mode 100644 bugreport.c\n>  create mode 100755 t/t0091-bugreport.sh\n\nPlease add a corresponding entry to 'command-list.txt' as well.\nAccording to the comment at the beginning of that file, all, even\nexternal commands should be included there.\n\n"},{"id":"391329","messageId":"20200207150857.GH2868@szeder.dev","threadId":"52442","inReplyTo":"20200207144725.GF2868@szeder.dev","subject":"Re: [PATCH v6 10/15] bugreport: add config values from safelist","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2020-02-07T15:08:57Z","receivedAt":"2020-02-07T15:09:02Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, Feb 07, 2020 at 03:47:25PM +0100, SZEDER Gábor wrote:\n> On Wed, Feb 05, 2020 at 04:41:03PM -0800, Emily Shaffer wrote:\n> > +static void get_safelisted_config(struct strbuf *config_info)\n> > +{\n> > +\tsize_t idx;\n> > +\tstruct string_list_item *it = NULL;\n> > +\tstruct key_value_info *kv_info = NULL;\n> > +\n> > +\tfor (idx = 0; idx < ARRAY_SIZE(bugreport_config_safelist); idx++) {\n> \n> GCC 9 complains about this loop condition:\n> \n>       CC bugreport.o\n>   \n>   bugreport.c: In function 'get_safelisted_config':\n>   \n>   bugreport.c:66:20: error: comparison of unsigned expression < 0 is always false [-Werror=type-limits]\n>   \n>      66 |  for (idx = 0; idx < ARRAY_SIZE(bugreport_config_safelist); idx++) {\n>   \n>         |                    ^\n> \n> I don't understand this error, that autogenerated\n> 'bugreport_config_safelist' array clearly has a a non-zero size.\n> What am I missing?\n\nmacOS 'sed', that's what I was missing :)\n\nSo that array is in fact empty on macOS, because the entries of that\narray are generated with:\n\n  # cat all regular files in Documentation/config\n  find Documentation/config -type f -exec cat {} \\; |\n  # print the command name which matches the annotate-bugreport macro\n  sed -n 's/^\\(.*\\) \\+annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' | sort\n\nand the 'sed' included in macOS apparently interprets that '\\+'\ndifferently than GNU 'sed', and as a result won't match anything.\n\nFWIW, that '\\+' doesn't seem to be necessary, though, and after\nremoving it the resulting generated array looked good to me (and to\nthe compiler) both on Linux and macOS.\n\n"},{"id":"391331","messageId":"20200207153042.GI2868@szeder.dev","threadId":"52442","inReplyTo":"20200206004108.261317-10-emilyshaffer@google.com","subject":"Re: [PATCH v6 09/15] bugreport: generate config safelist based on docs","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2020-02-07T15:30:42Z","receivedAt":"2020-02-07T15:30:49Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, Feb 05, 2020 at 04:41:02PM -0800, Emily Shaffer wrote:\n> Add a new step to the build to generate a safelist of git-config\n> variables which are appropriate to include in the output of\n> git-bugreport. New variables can be added to the safelist by annotating\n> their documentation in Documentation/config with the \"annotate\" macro,\n> which is a no-op in AsciiDoc and AsciiDoctor.\n> \n> Some configs are private in nature, and can contain remote URLs,\n> passwords, or other sensitive information. In the event that a user\n> doesn't notice their information while reviewing a bugreport, that user\n> may leak their credentials to other individuals, mailing lists, or bug\n> tracking tools inadvertently. Heuristic blocklisting of configuration\n> keys is imperfect and prone to false negatives; given the nature of the\n> information which can be leaked, a safelist is more reliable.\n> \n> However, it's possible that in some situations, an organization may be\n> less concerned with privacy of things like remote URLs and branch names,\n> and more concerned with ease of diagnosis for their support staff. In\n> those cases, it may make more sense for that organization to modify the\n> code to use a blocklist. To that end, we should try to mark configs which\n> are definitely safe, and configs which are definitely unsafe, and leave\n> blank configs which are somewhere in between. To mark a config as safe,\n> add \"annotate:bugreport[include]\" to the corresponding line in the\n> config documentation; to mark it as unsafe, add\n> \"annotate:bugreport[exclude]\" instead.\n> \n> Generating bugreport-config-safelist.h at build time by grepping the\n> documentation for this new macro helps us prevent staleness. The macro\n> itself is a no-op and should not alter the appearance of the\n> documentation in either AsciiDoc or AsciiDoctor, confirmable by running:\n> \n>   cd Documentation\n>   ./doc-diff --asciidoctor HEAD^ HEAD\n>   ./doc-diff --asciidoc HEAD^ HEAD\n> \n> Diffing the rendered HTML shows that only inline comments were added,\n> which shouldn't be a problem.\n> \n> Additionally, add annotations to the sendemail config documentation in\n> order to demonstrate a proof of concept.\n> \n> Helped-by: Martin Ågren <martin.agren@gmail.com>\n> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  .gitignore                              |  1 +\n>  Documentation/asciidoc.conf             |  9 ++++\n>  Documentation/asciidoctor-extensions.rb |  5 +++\n>  Documentation/config/sendemail.txt      | 56 ++++++++++++-------------\n>  Makefile                                |  7 ++++\n>  generate-bugreport-config-safelist.sh   | 17 ++++++++\n>  6 files changed, 67 insertions(+), 28 deletions(-)\n>  create mode 100755 generate-bugreport-config-safelist.sh\n> \n> diff --git a/.gitignore b/.gitignore\n> index d89bf9e11e..bd2f49b996 100644\n> --- a/.gitignore\n> +++ b/.gitignore\n> @@ -192,6 +192,7 @@\n>  /gitweb/static/gitweb.min.*\n>  /config-list.h\n>  /command-list.h\n> +/bugreport-config-safelist.h\n>  *.tar.gz\n>  *.dsc\n>  *.deb\n> diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\n> index 8fc4b67081..663e06481f 100644\n> --- a/Documentation/asciidoc.conf\n> +++ b/Documentation/asciidoc.conf\n> @@ -6,9 +6,14 @@\n>  #\n>  # Show Git link as: <command>(<section>); if section is defined, else just show\n>  # the command.\n> +#\n> +# The annotate macro does nothing as far as rendering is\n> +# concerned -- we just grep for it in the sources to populate\n> +# things like the bugreport safelist.\n>  \n>  [macros]\n>  (?su)[\\\\]?(?P<name>linkgit):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n> +(?su)[\\\\]?(?P<name>annotate):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n>  \n>  [attributes]\n>  asterisk=&#42;\n> @@ -28,6 +33,8 @@ ifdef::backend-docbook[]\n>  {0#<citerefentry>}\n>  {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n>  {0#</citerefentry>}\n> +[annotate-inlinemacro]\n> +{0#}\n>  endif::backend-docbook[]\n>  \n>  ifdef::backend-docbook[]\n> @@ -94,4 +101,6 @@ ifdef::backend-xhtml11[]\n>  git-relative-html-prefix=\n>  [linkgit-inlinemacro]\n>  <a href=\"{git-relative-html-prefix}{target}.html\">{target}{0?({0})}</a>\n> +[annotate-inlinemacro]\n> +<!-- -->\n>  endif::backend-xhtml11[]\n> diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\n> index d906a00803..382bd8f6f4 100644\n> --- a/Documentation/asciidoctor-extensions.rb\n> +++ b/Documentation/asciidoctor-extensions.rb\n> @@ -37,6 +37,10 @@ module Git\n>            output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n>          end\n>          output\n> +\n> +    class AnnotateProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n> +      def process(parent, target, attrs)\n> +        \"\"\n\nThis change breaks building the documentation with Asciidoctor v1.5.8:\n\n  /home/travis/.rvm/rubies/ruby-2.5.3/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': /home/travis/build/git/git/Documentation/asciidoctor-extensions.rb:41: class definition in method body (SyntaxError)\n  \n  ...xtensions::InlineMacroProcessor\n  \n  ...                               ^\n  \n  /home/travis/build/git/git/Documentation/asciidoctor-extensions.rb:53: syntax error, unexpected end-of-input, expecting keyword_end\n\n\n  https://travis-ci.org/git/git/jobs/647093871#L1127\n\n>        end\n>      end\n>    end\n> @@ -45,4 +49,5 @@ end\n>  Asciidoctor::Extensions.register do\n>    inline_macro Git::Documentation::LinkGitProcessor, :linkgit\n>    postprocessor Git::Documentation::DocumentPostProcessor\n> +  inline_macro Git::Documentation::AnnotateProcessor, :annotate\n>  end\n"},{"id":"391336","messageId":"CAPig+cQ8vHjzBdMAemznFbyUSHOuJu167RHkTNg_qmqi-DOB3g@mail.gmail.com","threadId":"52442","inReplyTo":"20200207150857.GH2868@szeder.dev","subject":"Re: [PATCH v6 10/15] bugreport: add config values from safelist","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2020-02-07T16:24:46Z","receivedAt":"2020-02-07T16:25:00Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Feb 7, 2020 at 10:09 AM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> macOS 'sed', that's what I was missing :)\n>\n>   sed -n 's/^\\(.*\\) \\+annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' | sort\n>\n> and the 'sed' included in macOS apparently interprets that '\\+'\n> differently than GNU 'sed', and as a result won't match anything.\n\nMore generally, this would be a problem with any 'sed' of BSD lineage.\n\n> FWIW, that '\\+' doesn't seem to be necessary, though, and after\n> removing it the resulting generated array looked good to me [...]\n\nA reasonable replacement for \"<SP>\\+\" would be \"<SP><SP>*\" (where <SP>\nrepresents 'space').\n"},{"id":"391338","messageId":"87zhdue3ye.fsf@igel.home","threadId":"52442","inReplyTo":"CAPig+cQ8vHjzBdMAemznFbyUSHOuJu167RHkTNg_qmqi-DOB3g@mail.gmail.com","subject":"Re: [PATCH v6 10/15] bugreport: add config values from safelist","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2020-02-07T16:51:05Z","receivedAt":"2020-02-07T16:51:11Z","isPatch":true,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"On Feb 07 2020, Eric Sunshine wrote:\n\n> On Fri, Feb 7, 2020 at 10:09 AM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n>> macOS 'sed', that's what I was missing :)\n>>\n>>   sed -n 's/^\\(.*\\) \\+annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' | sort\n>>\n>> and the 'sed' included in macOS apparently interprets that '\\+'\n>> differently than GNU 'sed', and as a result won't match anything.\n>\n> More generally, this would be a problem with any 'sed' of BSD lineage.\n>\n>> FWIW, that '\\+' doesn't seem to be necessary, though, and after\n>> removing it the resulting generated array looked good to me [...]\n>\n> A reasonable replacement for \"<SP>\\+\" would be \"<SP><SP>*\" (where <SP>\n> represents 'space').\n\nAnother problem with that regexp is that it contains two adjacent\nrepetitions matching the same character.  When there are two or more\nspaces before \"annotate:\" all but the last of them can be matched by\neither '\\(.*\\)' or ' \\+'.  To fix that '\\(.*\\)' needs to be modified to\nnot match a trailing space.\n\nAndreas.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1\n\"And now for something completely different.\"\n"},{"id":"391342","messageId":"xmqq5zgi44em.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200207141802.GE2868@szeder.dev","subject":"Re: [PATCH v6 03/15] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-07T18:51:29Z","receivedAt":"2020-02-07T18:51:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n> On Wed, Feb 05, 2020 at 04:40:56PM -0800, Emily Shaffer wrote:\n>> diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\n>> new file mode 100755\n>> index 0000000000..451badff0c\n>> --- /dev/null\n>> +++ b/t/t0091-bugreport.sh\n>> @@ -0,0 +1,49 @@\n>> +#!/bin/sh\n>> +\n>> +test_description='git bugreport'\n>> +\n>> +. ./test-lib.sh\n>> +\n>> +# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n>> +# information there; we can make sure all our headers were followed by some\n>> +# information to check if the command was successful.\n>> +HEADER_PATTERN=\"^\\[.*\\]$\"\n>> +check_all_headers_populated() {\n>> +\twhile read -r line; do\n>> +\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"; then\n>> +\t\t\techo \"$line\"\n>> +\t\t\tread -r nextline\n>> +\t\t\tif test -z \"$nextline\"; then\n>> +\t\t\t\treturn 1;\n>> +\t\t\tfi\n>> +\t\tfi\n>> +\tdone\n>> +}\n>> +\n>> +test_expect_success 'creates a report with content in the right places' '\n>> +\tgit bugreport &&\n>> +\tREPORT=\"$(ls git-bugreport-*)\" &&\n>\n> What if the globbing were to match more than one file?\n\nAn often-useful pattern is to make the command report the output\nfilename, i.e.\n\n\tREPORT=$(git butreport) &&\n\nif the design insists that \"git bugreport\" should allocate a\nfilename in order to make it easy to guarantee uniqueness.\n\nOf course, we can make the invoker supply filename, e.g.\n\n\tREPORT=$(generate-output-filename) &&\n\tgit bugreport -o \"$REPORT\" ;# or git bugreport >\"$REPORT\"\n\n"},{"id":"391581","messageId":"20200211224021.GF190927@google.com","threadId":"52442","inReplyTo":"xmqq5zgi44em.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-11T22:40:21Z","receivedAt":"2020-02-11T22:40:28Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Feb 07, 2020 at 10:51:29AM -0800, Junio C Hamano wrote:\n> SZEDER Gábor <szeder.dev@gmail.com> writes:\n> \n> > On Wed, Feb 05, 2020 at 04:40:56PM -0800, Emily Shaffer wrote:\n> >> diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\n> >> new file mode 100755\n> >> index 0000000000..451badff0c\n> >> --- /dev/null\n> >> +++ b/t/t0091-bugreport.sh\n> >> @@ -0,0 +1,49 @@\n> >> +#!/bin/sh\n> >> +\n> >> +test_description='git bugreport'\n> >> +\n> >> +. ./test-lib.sh\n> >> +\n> >> +# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n> >> +# information there; we can make sure all our headers were followed by some\n> >> +# information to check if the command was successful.\n> >> +HEADER_PATTERN=\"^\\[.*\\]$\"\n> >> +check_all_headers_populated() {\n> >> +\twhile read -r line; do\n> >> +\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"; then\n> >> +\t\t\techo \"$line\"\n> >> +\t\t\tread -r nextline\n> >> +\t\t\tif test -z \"$nextline\"; then\n> >> +\t\t\t\treturn 1;\n> >> +\t\t\tfi\n> >> +\t\tfi\n> >> +\tdone\n> >> +}\n> >> +\n> >> +test_expect_success 'creates a report with content in the right places' '\n> >> +\tgit bugreport &&\n> >> +\tREPORT=\"$(ls git-bugreport-*)\" &&\n> >\n> > What if the globbing were to match more than one file?\n> \n> An often-useful pattern is to make the command report the output\n> filename, i.e.\n> \n> \tREPORT=$(git butreport) &&\n> \n> if the design insists that \"git bugreport\" should allocate a\n> filename in order to make it easy to guarantee uniqueness.\n> \n> Of course, we can make the invoker supply filename, e.g.\n> \n> \tREPORT=$(generate-output-filename) &&\n> \tgit bugreport -o \"$REPORT\" ;# or git bugreport >\"$REPORT\"\n\nYeah, this is an option and I've changed the offending test - which\ncaptures a variable based on globbing - to use --suffix and force a\nfilename.\n"},{"id":"391607","messageId":"xmqq36bfvfwr.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200206004108.261317-4-emilyshaffer@google.com","subject":"Re: [PATCH v6 03/15] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-12T18:06:44Z","receivedAt":"2020-02-12T18:06:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"As this topic seems to break under GIT_TEST_GETTEXT_POISON=yes, I'll\napply the following band-aid on top before merging it to 'pu'.  \n\nMost of them are style fixes, but quoting $REPORT, not just makes\nthe redirection honor the coding guidelines, will ensure that an\nerror is caught if git-bugreport-* glob matches no paths or more\nthan on paths.\n\n\n\n\n t/t0091-bugreport.sh | 17 ++++++++++-------\n 1 file changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nindex 451badff0c..f2186941ce 100755\n--- a/t/t0091-bugreport.sh\n+++ b/t/t0091-bugreport.sh\n@@ -8,9 +8,12 @@ test_description='git bugreport'\n # information there; we can make sure all our headers were followed by some\n # information to check if the command was successful.\n HEADER_PATTERN=\"^\\[.*\\]$\"\n-check_all_headers_populated() {\n-\twhile read -r line; do\n-\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"; then\n+\n+check_all_headers_populated () {\n+\twhile read -r line\n+\tdo\n+\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n+\t\tthen\n \t\t\techo \"$line\"\n \t\t\tread -r nextline\n \t\t\tif test -z \"$nextline\"; then\n@@ -23,12 +26,12 @@ check_all_headers_populated() {\n test_expect_success 'creates a report with content in the right places' '\n \tgit bugreport &&\n \tREPORT=\"$(ls git-bugreport-*)\" &&\n-\tcheck_all_headers_populated <$REPORT &&\n-\trm $REPORT\n+\tcheck_all_headers_populated <\"$REPORT\" &&\n+\trm \"$REPORT\"\n '\n \n test_expect_success 'dies if file with same name as report already exists' '\n-\ttouch git-bugreport-duplicate.txt &&\n+\t>>git-bugreport-duplicate.txt &&\n \ttest_must_fail git bugreport --suffix duplicate &&\n \trm git-bugreport-duplicate.txt\n '\n@@ -42,7 +45,7 @@ test_expect_success '--output-directory puts the report in the provided dir' '\n \n test_expect_success 'incorrect arguments abort with usage' '\n \ttest_must_fail git bugreport --false 2>output &&\n-\tgrep usage output &&\n+\ttest_i18ngrep usage output &&\n \ttest_path_is_missing git-bugreport-*\n '\n \n-- \n2.25.0-455-gcf3c3a5ab4\n\n"},{"id":"391628","messageId":"20200212223642.GG190927@google.com","threadId":"52442","inReplyTo":"xmqq36bfvfwr.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-12T22:36:42Z","receivedAt":"2020-02-12T22:36:49Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Wed, Feb 12, 2020 at 10:06:44AM -0800, Junio C Hamano wrote:\n> As this topic seems to break under GIT_TEST_GETTEXT_POISON=yes, I'll\n> apply the following band-aid on top before merging it to 'pu'.  \n> \n> Most of them are style fixes, but quoting $REPORT, not just makes\n> the redirection honor the coding guidelines, will ensure that an\n> error is caught if git-bugreport-* glob matches no paths or more\n> than on paths.\n\nThanks. Most of these I have locally, but not all. I'll apply this as a\nfixup on patch 3/n (the one that introduces the tests) and add a\nHelped-by line.\n\nI'm hoping to get a reroll out today; it was the first thing on my list\nthis week, and then a high-priority internal issue shows up (so it\ngoes). Sorry for the inconvenience with the CI failures.\n\n - Emily\n\n>  t/t0091-bugreport.sh | 17 ++++++++++-------\n>  1 file changed, 10 insertions(+), 7 deletions(-)\n> \n> diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\n> index 451badff0c..f2186941ce 100755\n> --- a/t/t0091-bugreport.sh\n> +++ b/t/t0091-bugreport.sh\n> @@ -8,9 +8,12 @@ test_description='git bugreport'\n>  # information there; we can make sure all our headers were followed by some\n>  # information to check if the command was successful.\n>  HEADER_PATTERN=\"^\\[.*\\]$\"\n> -check_all_headers_populated() {\n> -\twhile read -r line; do\n> -\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"; then\n> +\n> +check_all_headers_populated () {\n> +\twhile read -r line\n> +\tdo\n> +\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n> +\t\tthen\n>  \t\t\techo \"$line\"\n>  \t\t\tread -r nextline\n>  \t\t\tif test -z \"$nextline\"; then\n> @@ -23,12 +26,12 @@ check_all_headers_populated() {\n>  test_expect_success 'creates a report with content in the right places' '\n>  \tgit bugreport &&\n>  \tREPORT=\"$(ls git-bugreport-*)\" &&\n> -\tcheck_all_headers_populated <$REPORT &&\n> -\trm $REPORT\n> +\tcheck_all_headers_populated <\"$REPORT\" &&\n> +\trm \"$REPORT\"\n>  '\n>  \n>  test_expect_success 'dies if file with same name as report already exists' '\n> -\ttouch git-bugreport-duplicate.txt &&\n> +\t>>git-bugreport-duplicate.txt &&\n>  \ttest_must_fail git bugreport --suffix duplicate &&\n>  \trm git-bugreport-duplicate.txt\n>  '\n> @@ -42,7 +45,7 @@ test_expect_success '--output-directory puts the report in the provided dir' '\n>  \n>  test_expect_success 'incorrect arguments abort with usage' '\n>  \ttest_must_fail git bugreport --false 2>output &&\n> -\tgrep usage output &&\n> +\ttest_i18ngrep usage output &&\n>  \ttest_path_is_missing git-bugreport-*\n>  '\n>  \n> -- \n> 2.25.0-455-gcf3c3a5ab4\n> \n"},{"id":"391704","messageId":"20200213220206.GH190927@google.com","threadId":"52442","inReplyTo":"87zhdue3ye.fsf@igel.home","subject":"Re: [PATCH v6 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-13T22:02:06Z","receivedAt":"2020-02-13T22:02:13Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Feb 07, 2020 at 05:51:05PM +0100, Andreas Schwab wrote:\n> On Feb 07 2020, Eric Sunshine wrote:\n> \n> > On Fri, Feb 7, 2020 at 10:09 AM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> >> macOS 'sed', that's what I was missing :)\n> >>\n> >>   sed -n 's/^\\(.*\\) \\+annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' | sort\n> >>\n> >> and the 'sed' included in macOS apparently interprets that '\\+'\n> >> differently than GNU 'sed', and as a result won't match anything.\n> >\n> > More generally, this would be a problem with any 'sed' of BSD lineage.\n> >\n> >> FWIW, that '\\+' doesn't seem to be necessary, though, and after\n> >> removing it the resulting generated array looked good to me [...]\n> >\n> > A reasonable replacement for \"<SP>\\+\" would be \"<SP><SP>*\" (where <SP>\n> > represents 'space').\n> \n> Another problem with that regexp is that it contains two adjacent\n> repetitions matching the same character.  When there are two or more\n> spaces before \"annotate:\" all but the last of them can be matched by\n> either '\\(.*\\)' or ' \\+'.  To fix that '\\(.*\\)' needs to be modified to\n> not match a trailing space.\n\nHum. I had assumed since the capture group was not greedy, it would not\ncapture any trailing spaces that could be captured by ' \\+'. I don't see\na problem in making it non-explicit, though.\n\nI'll hack on this some more. I do find myself pretty annoyed at the\nmatcher difference between 'sed' and 'also sed', though, and don't see\nin the manpage a way to guarantee which matcher 'sed' should use (a la\n'grep -[EFGP]'). :)\n\n - Emily\n"},{"id":"391708","messageId":"20200213225834.GI190927@google.com","threadId":"52442","inReplyTo":"20200206013533.GA3993@danh.dev","subject":"Re: [PATCH v6 01/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-13T22:58:34Z","receivedAt":"2020-02-13T22:58:42Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Feb 06, 2020 at 08:35:33AM +0700, Danh Doan wrote:\n> On 2020-02-05 16:40:54-0800, Emily Shaffer <emilyshaffer@google.com> wrote:\n> > diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> > index 71158f7d8b..45fecf8bdf 100755\n> > --- a/generate-cmdlist.sh\n> > +++ b/generate-cmdlist.sh\n> > @@ -76,23 +76,6 @@ print_command_list () {\n> >  \techo \"};\"\n> >  }\n> >  \n> > -print_config_list () {\n> > -\tcat <<EOF\n> > -static const char *config_name_list[] = {\n> > -EOF\n> > -\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> > -\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> > -\tsort |\n> > -\twhile read line\n> > -\tdo\n> > -\t\techo \"\t\\\"$line\\\",\"\n> > -\tdone\n> > -\tcat <<EOF\n> > -\tNULL,\n> > -};\n> > -EOF\n> > -}\n> > -\n> >  exclude_programs=\n> >  while test \"--exclude-program\" = \"$1\"\n> >  do\n> > @@ -113,5 +96,3 @@ echo\n> >  define_category_names \"$1\"\n> >  echo\n> >  print_command_list \"$1\"\n> > -echo\n> > -print_config_list\n> > diff --git a/generate-configlist.sh b/generate-configlist.sh\n> > new file mode 100755\n> > index 0000000000..eca6a00c30\n> > --- /dev/null\n> > +++ b/generate-configlist.sh\n> > @@ -0,0 +1,24 @@\n> > +#!/bin/sh\n> > +\n> > +echo \"/* Automatically generated by generate-configlist.sh */\"\n> > +echo\n> > +\n> > +print_config_list () {\n> > +\tcat <<EOF\n> > +static const char *config_name_list[] = {\n> > +EOF\n> > +\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n> > +\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n> > +\tsort |\n> > +\twhile read line\n> > +\tdo\n> > +\t\techo \"\t\\\"$line\\\",\"\n> > +\tdone\n> \n> This while-read-echo was moved from generate-cmdlist.sh,\n> which has some logic to work with read-variable.\n> \n> We're moving it out, I think apply this diff on top of it will make the code easier to read.\n> \n> diff --git a/generate-configlist.sh b/generate-configlist.sh\n> index eca6a00c30..163dbf30bb 100755\n> --- a/generate-configlist.sh\n> +++ b/generate-configlist.sh\n> @@ -10,10 +10,7 @@ EOF\n>  \tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n>  \tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n>  \tsort |\n> -\twhile read line\n> -\tdo\n> -\t\techo \"\t\\\"$line\\\",\"\n> -\tdone\n> +\tsed 's/^/\t\"/; s/$/\",/'\n>  \tcat <<EOF\n>  \tNULL,\n>  };\n\nThanks for the suggestion. You're right that I didn't look into the\ncontents of this script much, because I was just moving it; I modified\nyour sed expression slightly so it performs just one operation:\n\n  sed 's/^.*$/    \"\\0\",/'\n\n - Emily\n"},{"id":"391709","messageId":"CAPig+cRDbOyDQm6wx7+fZoKDfehLjkPc3qenR5Mhc8OkeFJqbw@mail.gmail.com","threadId":"52442","inReplyTo":"20200213225834.GI190927@google.com","subject":"Re: [PATCH v6 01/15] help: move list_config_help to builtin/help","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2020-02-13T23:07:59Z","receivedAt":"2020-02-13T23:08:13Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Feb 13, 2020 at 5:58 PM Emily Shaffer <emilyshaffer@google.com> wrote:\n> On Thu, Feb 06, 2020 at 08:35:33AM +0700, Danh Doan wrote:\n> > -     while read line\n> > -     do\n> > -             echo \"  \\\"$line\\\",\"\n> > -     done\n> > +     sed 's/^/       \"/; s/$/\",/'\n>\n> Thanks for the suggestion. You're right that I didn't look into the\n> contents of this script much, because I was just moving it; I modified\n> your sed expression slightly so it performs just one operation:\n>\n>   sed 's/^.*$/    \"\\0\",/'\n\nThis isn't portable and won't work with 'sed' from BSD lineage,\nincluding Mac OS. More portable would be:\n\n    sed 's/^\\(.*\\)$/    \"\\1\",/'\n"},{"id":"391710","messageId":"20200213231424.GJ190927@google.com","threadId":"52442","inReplyTo":"20200207153042.GI2868@szeder.dev","subject":"Re: [PATCH v6 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-13T23:14:24Z","receivedAt":"2020-02-13T23:14:33Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Feb 07, 2020 at 04:30:42PM +0100, SZEDER Gábor wrote:\n> On Wed, Feb 05, 2020 at 04:41:02PM -0800, Emily Shaffer wrote:\n> > diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\n> > index d906a00803..382bd8f6f4 100644\n> > --- a/Documentation/asciidoctor-extensions.rb\n> > +++ b/Documentation/asciidoctor-extensions.rb\n> > @@ -37,6 +37,10 @@ module Git\n> >            output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n> >          end\n> >          output\n> > +\n> > +    class AnnotateProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n> > +      def process(parent, target, attrs)\n> > +        \"\"\n> \n> This change breaks building the documentation with Asciidoctor v1.5.8:\n> \n>   /home/travis/.rvm/rubies/ruby-2.5.3/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': /home/travis/build/git/git/Documentation/asciidoctor-extensions.rb:41: class definition in method body (SyntaxError)\n>   \n>   ...xtensions::InlineMacroProcessor\n>   \n>   ...                               ^\n>   \n>   /home/travis/build/git/git/Documentation/asciidoctor-extensions.rb:53: syntax error, unexpected end-of-input, expecting keyword_end\n> \n> \n>   https://travis-ci.org/git/git/jobs/647093871#L1127\n\nDone. It passes locally for me now if I run:\n\n  USE_ASCIIDOCTOR=1 make doc\n\nThanks for the heads up.\n\n - Emily\n"},{"id":"391712","messageId":"xmqq36beqdez.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"CAPig+cRDbOyDQm6wx7+fZoKDfehLjkPc3qenR5Mhc8OkeFJqbw@mail.gmail.com","subject":"Re: [PATCH v6 01/15] help: move list_config_help to builtin/help","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-13T23:24:04Z","receivedAt":"2020-02-13T23:24:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Thu, Feb 13, 2020 at 5:58 PM Emily Shaffer <emilyshaffer@google.com> wrote:\n>> On Thu, Feb 06, 2020 at 08:35:33AM +0700, Danh Doan wrote:\n>> > -     while read line\n>> > -     do\n>> > -             echo \"  \\\"$line\\\",\"\n>> > -     done\n>> > +     sed 's/^/       \"/; s/$/\",/'\n>>\n>> Thanks for the suggestion. You're right that I didn't look into the\n>> contents of this script much, because I was just moving it; I modified\n>> your sed expression slightly so it performs just one operation:\n>>\n>>   sed 's/^.*$/    \"\\0\",/'\n>\n> This isn't portable and won't work with 'sed' from BSD lineage,\n> including Mac OS. More portable would be:\n>\n>     sed 's/^\\(.*\\)$/    \"\\1\",/'\n\nOr just replace Emily's \\0 with &; that should be in POSIX.\n"},{"id":"391713","messageId":"CAPig+cT3gSARiHFN=79Z_BBACDyOqW8nZ+7RwODAmLrDv1SHuA@mail.gmail.com","threadId":"52442","inReplyTo":"xmqq36beqdez.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 01/15] help: move list_config_help to builtin/help","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2020-02-13T23:29:39Z","receivedAt":"2020-02-13T23:29:54Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Feb 13, 2020 at 6:24 PM Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Sunshine <sunshine@sunshineco.com> writes:\n> > On Thu, Feb 13, 2020 at 5:58 PM Emily Shaffer <emilyshaffer@google.com> wrote:\n> >> Thanks for the suggestion. You're right that I didn't look into the\n> >> contents of this script much, because I was just moving it; I modified\n> >> your sed expression slightly so it performs just one operation:\n> >>\n> >>   sed 's/^.*$/    \"\\0\",/'\n> >\n> > This isn't portable and won't work with 'sed' from BSD lineage,\n> > including Mac OS. More portable would be:\n> >\n> >     sed 's/^\\(.*\\)$/    \"\\1\",/'\n>\n> Or just replace Emily's \\0 with &; that should be in POSIX.\n\nYes, that's nicer.\n"},{"id":"391716","messageId":"20200214012037.GK190927@google.com","threadId":"52442","inReplyTo":"CAPig+cT3gSARiHFN=79Z_BBACDyOqW8nZ+7RwODAmLrDv1SHuA@mail.gmail.com","subject":"Re: [PATCH v6 01/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:20:37Z","receivedAt":"2020-02-14T01:20:45Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Feb 13, 2020 at 06:29:39PM -0500, Eric Sunshine wrote:\n> On Thu, Feb 13, 2020 at 6:24 PM Junio C Hamano <gitster@pobox.com> wrote:\n> > Eric Sunshine <sunshine@sunshineco.com> writes:\n> > > On Thu, Feb 13, 2020 at 5:58 PM Emily Shaffer <emilyshaffer@google.com> wrote:\n> > >> Thanks for the suggestion. You're right that I didn't look into the\n> > >> contents of this script much, because I was just moving it; I modified\n> > >> your sed expression slightly so it performs just one operation:\n> > >>\n> > >>   sed 's/^.*$/    \"\\0\",/'\n> > >\n> > > This isn't portable and won't work with 'sed' from BSD lineage,\n> > > including Mac OS. More portable would be:\n> > >\n> > >     sed 's/^\\(.*\\)$/    \"\\1\",/'\n> >\n> > Or just replace Emily's \\0 with &; that should be in POSIX.\n> \n> Yes, that's nicer.\n\nSure, thanks.\n"},{"id":"391718","messageId":"20200214015343.201946-1-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200206004108.261317-1-emilyshaffer@google.com","subject":"[PATCH v7 00/15] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:28Z","receivedAt":"2020-02-14T01:53:55Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"This patchset is based on mr/show-config-scope, which looks close to\nready for 'next'.\n\nSince v6:\n\n - Applied Danh's suggestion[1] (with modifications recommended by Eric and\n   Junio downthread)\n - Fixed a missed end-of-macro in the Asciidoctor config which was\n   pointed out most recently by SZEDER[2]\n - Fixed generate-bugreport-safelist-config.sh to be more friendly to\n   BSD-derived 'sed' and to capture trailing ' ' when extra whitespace is\n   present(patch 9/15). This now uses POSIX character classes and {}\n   notation instead of + and has been tested on OSX; I'd love to hear if\n   it's still not working correctly.\n - Applied Junio's patch[3] to make GIT_TEST_GETTEXT_POISON happy and to\n   make the tests more idiomatic.\n - Stop globbing into variables, start making the output directory if it\n   doesn't exist before[4]\n - Add an entry in 'command-list.txt'[5]. I sure wish someone had\n   explained how to do this somewhere in a tutorial about writing new\n   commands ;)\n - Added a test to ensure that git-bugreport runs gracefully in a\n   non-repo directory.\n - Added nongit_ok flags to relevant pieces of info to ensure the above\n   test passes.\n\n[1] https://lore.kernel.org/git/20200206013533.GA3993@danh.dev\n[2] https://lore.kernel.org/git/20200207153042.GI2868@szeder.dev\n[3] https://lore.kernel.org/git/xmqq36bfvfwr.fsf@gitster-ct.c.googlers.com\n[4] https://lore.kernel.org/git/20200207141802.GE2868@szeder.dev\n[5] https://lore.kernel.org/git/20200207145409.GG2868@szeder.dev\n\n\nEmily Shaffer (15):\n  help: move list_config_help to builtin/help\n  help: add shell-path to --build-options\n  bugreport: add tool to generate debugging info\n  bugreport: gather git version and build info\n  bugreport: add uname info\n  bugreport: add compiler info\n  bugreport: add git-remote-https version\n  bugreport: include user interactive shell\n  bugreport: generate config safelist based on docs\n  bugreport: add config values from safelist\n  bugreport: collect list of populated hooks\n  bugreport: count loose objects\n  bugreport: add packed object summary\n  bugreport: list contents of $OBJDIR/info\n  bugreport: summarize contents of alternates file\n\n .gitignore                              |   3 +\n Documentation/asciidoc.conf             |   9 +\n Documentation/asciidoctor-extensions.rb |   7 +\n Documentation/config/sendemail.txt      |  56 ++--\n Documentation/git-bugreport.txt         |  55 ++++\n Makefile                                |  27 +-\n bugreport.c                             | 418 ++++++++++++++++++++++++\n builtin/help.c                          |  86 +++++\n command-list.txt                        |   1 +\n compat/compiler.h                       |  24 ++\n generate-bugreport-config-safelist.sh   |  18 +\n generate-cmdlist.sh                     |  19 --\n generate-configlist.sh                  |  21 ++\n help.c                                  | 132 ++------\n help.h                                  |   2 +-\n object-store.h                          |   6 +\n packfile.c                              |   3 +-\n remote-curl.c                           |   8 +\n t/t0091-bugreport.sh                    |  55 ++++\n 19 files changed, 794 insertions(+), 156 deletions(-)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100644 compat/compiler.h\n create mode 100755 generate-bugreport-config-safelist.sh\n create mode 100755 generate-configlist.sh\n create mode 100755 t/t0091-bugreport.sh\n\nv6 to v7 range-diff:\n\ndiff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\nindex 382bd8f6f4..03c80af0e5 100644\n--- a/Documentation/asciidoctor-extensions.rb\n+++ b/Documentation/asciidoctor-extensions.rb\n@@ -37,6 +37,8 @@ module Git\n           output = output.sub(/<\\/refmeta>/, new_tags + \"</refmeta>\")\n         end\n         output\n+      end\n+    end\n \n     class AnnotateProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n       def process(parent, target, attrs)\ndiff --git a/bugreport.c b/bugreport.c\nindex 9d4d5c8e6f..3bc8cb3579 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -368,6 +368,15 @@ int cmd_main(int argc, const char **argv)\n \tif (!stat(report_path.buf, &statbuf))\n \t\tdie(\"'%s' already exists\", report_path.buf);\n \n+\tswitch (safe_create_leading_directories(report_path.buf)) {\n+\tcase SCLD_OK:\n+\tcase SCLD_EXISTS:\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(_(\"could not create leading directories for '%s'\"),\n+\t\t    report_path.buf);\n+\t}\n+\n \tget_bug_template(&buffer);\n \n \tget_header(&buffer, \"System Info\");\ndiff --git a/command-list.txt b/command-list.txt\nindex 2087894655..185e5e3f05 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -54,6 +54,7 @@ git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n+git-bugreport                           ancillaryinterrogators\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n git-check-attr                          purehelpers\ndiff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\nindex 17d92a91c5..2794a8ae77 100755\n--- a/generate-bugreport-config-safelist.sh\n+++ b/generate-bugreport-config-safelist.sh\n@@ -10,7 +10,8 @@ EOF\n # cat all regular files in Documentation/config\n find Documentation/config -type f -exec cat {} \\; |\n # print the command name which matches the annotate-bugreport macro\n-sed -n 's/^\\(.*\\) \\+annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' | sort\n+sed -n 's/^\\([^[:blank:]]*\\)[[:blank:]]\\{1,\\}annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' \\\n+\t| sort\n \n cat <<EOF\n };\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nindex eca6a00c30..8692fe5cf4 100755\n--- a/generate-configlist.sh\n+++ b/generate-configlist.sh\n@@ -10,10 +10,7 @@ EOF\n \tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n \tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n \tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n+\tsed 's/^.*$/\t\"&\",/'\n \tcat <<EOF\n \tNULL,\n };\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nindex 451badff0c..6585a2d144 100755\n--- a/t/t0091-bugreport.sh\n+++ b/t/t0091-bugreport.sh\n@@ -8,9 +8,12 @@ test_description='git bugreport'\n # information there; we can make sure all our headers were followed by some\n # information to check if the command was successful.\n HEADER_PATTERN=\"^\\[.*\\]$\"\n-check_all_headers_populated() {\n-\twhile read -r line; do\n-\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"; then\n+\n+check_all_headers_populated () {\n+\twhile read -r line\n+\tdo\n+\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n+\t\tthen\n \t\t\techo \"$line\"\n \t\t\tread -r nextline\n \t\t\tif test -z \"$nextline\"; then\n@@ -21,29 +24,32 @@ check_all_headers_populated() {\n }\n \n test_expect_success 'creates a report with content in the right places' '\n-\tgit bugreport &&\n-\tREPORT=\"$(ls git-bugreport-*)\" &&\n-\tcheck_all_headers_populated <$REPORT &&\n-\trm $REPORT\n+\tgit bugreport -s check-headers &&\n+\tcheck_all_headers_populated <git-bugreport-check-headers.txt &&\n+\ttest_when_finished rm git-bugreport-check-headers.txt\n '\n \n test_expect_success 'dies if file with same name as report already exists' '\n-\ttouch git-bugreport-duplicate.txt &&\n+\t>>git-bugreport-duplicate.txt &&\n \ttest_must_fail git bugreport --suffix duplicate &&\n-\trm git-bugreport-duplicate.txt\n+\ttest_when_finished rm git-bugreport-duplicate.txt\n '\n \n test_expect_success '--output-directory puts the report in the provided dir' '\n-\tmkdir foo/ &&\n \tgit bugreport -o foo/ &&\n \ttest_path_is_file foo/git-bugreport-* &&\n-\trm -fr foo/\n+\ttest_when_finished rm -fr foo/\n '\n \n test_expect_success 'incorrect arguments abort with usage' '\n \ttest_must_fail git bugreport --false 2>output &&\n-\tgrep usage output &&\n+\ttest_i18ngrep usage output &&\n \ttest_path_is_missing git-bugreport-*\n '\n \n+test_expect_success 'runs outside of a git dir' '\n+\tnongit git bugreport &&\n+\ttest_when_finished rm non-repo/git-bugreport-*\n+'\n+\n test_done\n\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391719","messageId":"20200214015343.201946-3-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 02/15] help: add shell-path to --build-options","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:30Z","receivedAt":"2020-02-14T01:54:04Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It may be useful to know which shell Git was built to try to point to,\nin the event that shell-based Git commands are failing. $SHELL_PATH is\nset during the build and used to launch the manpage viewer, as well as\nby git-compat-util.h, and it's used during tests. 'git version\n--build-options' is encouraged for use in bug reports, so it makes sense\nto include this information there.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n help.c | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/help.c b/help.c\nindex a21487db77..190722fb0a 100644\n--- a/help.c\n+++ b/help.c\n@@ -654,6 +654,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \t\t\tprintf(\"no commit associated with this build\\n\");\n \t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n \t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\tprintf(\"shell-path: %s\\n\", SHELL_PATH);\n \t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n \t}\n \treturn 0;\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391720","messageId":"20200214015343.201946-2-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 01/15] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:29Z","receivedAt":"2020-02-14T01:54:05Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\nbuiltin/clean.o, and builtin/config.o. This meant that help.o was\nunusable outside of the context of the main Git executable.\n\nTo make help.o usable by other commands again, move list_config_help()\ninto builtin/help.c (where it makes sense to assume other builtin libraries\nare present).\n\nWhen command-list.h is included but a member is not used, we start to\nhear a compiler warning. Since the config list is generated in a fairly\ndifferent way than the command list, and since commands and config\noptions are semantically different, move the config list into its own\nheader and move the generator into its own script and build rule.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore             |  1 +\n Makefile               | 13 +++++--\n builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n generate-cmdlist.sh    | 19 ----------\n generate-configlist.sh | 21 +++++++++++\n help.c                 | 85 -----------------------------------------\n help.h                 |  1 -\n 7 files changed, 118 insertions(+), 108 deletions(-)\n create mode 100755 generate-configlist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex aebe7c0908..ea97de83f3 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -189,6 +189,7 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 09f98b777c..5a022367d4 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -814,6 +814,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n@@ -2128,7 +2129,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2148,6 +2149,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2781,7 +2788,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%\n+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n endif\n@@ -2803,7 +2810,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..8692fe5cf4\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,21 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\tsed 's/^.*$/\t\"&\",/'\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/help.c b/help.c\nindex cf67624a94..a21487db77 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\ndiff --git a/help.h b/help.h\nindex 7a455beeb7..9071894e8c 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391721","messageId":"20200214015343.201946-5-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 04/15] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:32Z","receivedAt":"2020-02-14T01:54:05Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Knowing which version of Git a user has and how it was built allows us\nto more precisely pin down the circumstances when a certain issue\noccurs, so teach bugreport how to tell us the same output as 'git\nversion --build-options'.\n\nIt's not ideal to directly call 'git version --build-options' because\nthat output goes to stdout. Instead, wrap the version string in a helper\nwithin help.[ch] library, and call that helper from within the bugreport\nlibrary.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  4 +++\n bugreport.c                     | 19 ++++++++++++-\n help.c                          | 48 ++++++++++++++++++++-------------\n help.h                          |  1 +\n 4 files changed, 52 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 52d49ed7aa..6ce2ae2eff 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -23,6 +23,10 @@ The following information is requested from the user:\n  - Expected behavior\n  - Actual behavior\n \n+The following information is captured automatically:\n+\n+ - 'git version --build-options'\n+\n OPTIONS\n -------\n -o <path>::\ndiff --git a/bugreport.c b/bugreport.c\nindex a9398e6a2a..b7504fe322 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,8 +1,17 @@\n-#include \"builtin.h\"\n+#include \"cache.h\"\n #include \"parse-options.h\"\n #include \"stdio.h\"\n #include \"strbuf.h\"\n #include \"time.h\"\n+#include \"help.h\"\n+\n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, \"git version:\\n\");\n+\tget_version_info(sys_info, 1);\n+\tstrbuf_complete_line(sys_info);\n+}\n \n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n@@ -32,6 +41,11 @@ static int get_bug_template(struct strbuf *template)\n \treturn 0;\n }\n \n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n int cmd_main(int argc, const char **argv)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n@@ -76,6 +90,9 @@ int cmd_main(int argc, const char **argv)\n \n \tget_bug_template(&buffer);\n \n+\tget_header(&buffer, \"System Info\");\n+\tget_system_info(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\ndiff --git a/help.c b/help.c\nindex 190722fb0a..44cee69c11 100644\n--- a/help.c\n+++ b/help.c\n@@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void get_version_info(struct strbuf *buf, int show_build_options)\n+{\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (show_build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addstr(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\tstrbuf_addf(buf, \"shell-path: %s\\n\", SHELL_PATH);\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -637,26 +662,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tget_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n+\n+\tstrbuf_release(&buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\tprintf(\"shell-path: %s\\n\", SHELL_PATH);\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 9071894e8c..500521b908 100644\n--- a/help.h\n+++ b/help.h\n@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void get_version_info(struct strbuf *buf, int show_build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391722","messageId":"20200214015343.201946-4-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:31Z","receivedAt":"2020-02-14T01:54:05Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach Git how to prompt the user for a good bug report: reproduction\nsteps, expected behavior, and actual behavior. Later, Git can learn how\nto collect some diagnostic information from the repository.\n\nIf users can send us a well-written bug report which contains diagnostic\ninformation we would otherwise need to ask the user for, we can reduce\nthe number of question-and-answer round trips between the reporter and\nthe Git contributor.\n\nUsers may also wish to send a report like this to their local \"Git\nexpert\" if they have put their repository into a state they are confused\nby.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                      |  1 +\n Documentation/git-bugreport.txt | 41 ++++++++++++++\n Makefile                        |  5 ++\n bugreport.c                     | 94 +++++++++++++++++++++++++++++++++\n command-list.txt                |  1 +\n t/t0091-bugreport.sh            | 55 +++++++++++++++++++\n 6 files changed, 197 insertions(+)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ea97de83f3..d89bf9e11e 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -25,6 +25,7 @@\n /git-bisect--helper\n /git-blame\n /git-branch\n+/git-bugreport\n /git-bundle\n /git-cat-file\n /git-check-attr\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..52d49ed7aa\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,41 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+OPTIONS\n+-------\n+-o <path>::\n+--output-directory <path>::\n+\tPlace the resulting bug report file in `<path>` instead of the root of\n+\tthe Git repository.\n+\n+-s <format>::\n+--suffix <format>::\n+\tSpecify an alternate suffix for the bugreport name, to create a file\n+\tnamed 'git-bugreport-<formatted suffix>'. This should take the form of a\n+\tlink:strftime[3] format string; the current local time will be used.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex 5a022367d4..a01a050aa3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -2457,6 +2458,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\ndiff --git a/bugreport.c b/bugreport.c\nnew file mode 100644\nindex 0000000000..a9398e6a2a\n--- /dev/null\n+++ b/bugreport.c\n@@ -0,0 +1,94 @@\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to share.\\n\");\n+\n+\tstrbuf_addstr(template, template_text);\n+\treturn 0;\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tFILE *report;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\tchar *option_suffix = \"%F-%H%M\";\n+\tstruct stat statbuf;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_STRING('s', \"suffix\", &option_suffix, N_(\"format\"),\n+\t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"\", bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\tif (option_output) {\n+\t\tstrbuf_addstr(&report_path, option_output);\n+\t\tstrbuf_complete(&report_path, '/');\n+\t}\n+\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\tif (!stat(report_path.buf, &statbuf))\n+\t\tdie(\"'%s' already exists\", report_path.buf);\n+\n+\tswitch (safe_create_leading_directories(report_path.buf)) {\n+\tcase SCLD_OK:\n+\tcase SCLD_EXISTS:\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(_(\"could not create leading directories for '%s'\"),\n+\t\t    report_path.buf);\n+\t}\n+\n+\tget_bug_template(&buffer);\n+\n+\treport = fopen_for_writing(report_path.buf);\n+\n+\tif (report == NULL) {\n+\t\tstrbuf_release(&report_path);\n+\t\tdie(\"couldn't open '%s' for writing\", report_path.buf);\n+\t}\n+\n+\tstrbuf_write(&buffer, report);\n+\tfclose(report);\n+\n+\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"), report_path.buf);\n+\n+\tUNLEAK(buffer);\n+\tUNLEAK(report_path);\n+\treturn -launch_editor(report_path.buf, NULL, NULL);\n+}\ndiff --git a/command-list.txt b/command-list.txt\nindex 2087894655..185e5e3f05 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -54,6 +54,7 @@ git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n+git-bugreport                           ancillaryinterrogators\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n git-check-attr                          purehelpers\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..6585a2d144\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,55 @@\n+#!/bin/sh\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+\n+check_all_headers_populated () {\n+\twhile read -r line\n+\tdo\n+\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n+\t\tthen\n+\t\t\techo \"$line\"\n+\t\t\tread -r nextline\n+\t\t\tif test -z \"$nextline\"; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\tgit bugreport -s check-headers &&\n+\tcheck_all_headers_populated <git-bugreport-check-headers.txt &&\n+\ttest_when_finished rm git-bugreport-check-headers.txt\n+'\n+\n+test_expect_success 'dies if file with same name as report already exists' '\n+\t>>git-bugreport-duplicate.txt &&\n+\ttest_must_fail git bugreport --suffix duplicate &&\n+\ttest_when_finished rm git-bugreport-duplicate.txt\n+'\n+\n+test_expect_success '--output-directory puts the report in the provided dir' '\n+\tgit bugreport -o foo/ &&\n+\ttest_path_is_file foo/git-bugreport-* &&\n+\ttest_when_finished rm -fr foo/\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\ttest_i18ngrep usage output &&\n+\ttest_path_is_missing git-bugreport-*\n+'\n+\n+test_expect_success 'runs outside of a git dir' '\n+\tnongit git bugreport &&\n+\ttest_when_finished rm non-repo/git-bugreport-*\n+'\n+\n+test_done\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391724","messageId":"20200214015343.201946-6-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 05/15] bugreport: add uname info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:33Z","receivedAt":"2020-02-14T01:54:07Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The contents of uname() can give us some insight into what sort of\nsystem the user is running on, and help us replicate their setup if need\nbe. The domainname field is not guaranteed to be available, so don't\ncollect it.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 13 +++++++++++++\n 2 files changed, 14 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 6ce2ae2eff..4dd72c60f5 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -26,6 +26,7 @@ The following information is requested from the user:\n The following information is captured automatically:\n \n  - 'git version --build-options'\n+ - uname sysname, release, version, and machine strings\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex b7504fe322..b76a1dfb2a 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -7,10 +7,23 @@\n \n static void get_system_info(struct strbuf *sys_info)\n {\n+\tstruct utsname uname_info;\n+\n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, \"git version:\\n\");\n \tget_version_info(sys_info, 1);\n \tstrbuf_complete_line(sys_info);\n+\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname -a: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, \"uname() failed with code %d\\n\", errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391723","messageId":"20200214015343.201946-7-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 06/15] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:34Z","receivedAt":"2020-02-14T01:54:09Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"To help pinpoint the source of a regression, it is useful to know some\ninfo about the compiler which the user's Git client was built with. By\nadding a generic get_compiler_info() in 'compat/' we can choose which\nrelevant information to share per compiler; to get started, let's\ndemonstrate the version of glibc if the user built with 'gcc'.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     |  5 +++++\n compat/compiler.h               | 24 ++++++++++++++++++++++++\n 3 files changed, 30 insertions(+)\n create mode 100644 compat/compiler.h\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 4dd72c60f5..8bbc4c960c 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -27,6 +27,7 @@ The following information is captured automatically:\n \n  - 'git version --build-options'\n  - uname sysname, release, version, and machine strings\n+ - Compiler-specific info string\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex b76a1dfb2a..4f9101caeb 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"time.h\"\n #include \"help.h\"\n+#include \"compat/compiler.h\"\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -24,6 +25,10 @@ static void get_system_info(struct strbuf *sys_info)\n \t\t\t    uname_info.release,\n \t\t\t    uname_info.version,\n \t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, \"compiler info: \");\n+\tget_compiler_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/compat/compiler.h b/compat/compiler.h\nnew file mode 100644\nindex 0000000000..bda5098e1b\n--- /dev/null\n+++ b/compat/compiler.h\n@@ -0,0 +1,24 @@\n+#ifndef COMPILER_H\n+#define COMPILER_H\n+\n+#include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+\n+#ifdef __GLIBC__\n+#include <gnu/libc-version.h>\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tstrbuf_addf(info, \"glibc: %s\", gnu_get_libc_version());\n+}\n+\n+#else\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tstrbuf_addstr(info, \"get_compiler_info() not implemented\");\n+}\n+\n+#endif\n+\n+#endif /* COMPILER_H */\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391725","messageId":"20200214015343.201946-10-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 09/15] bugreport: generate config safelist based on docs","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:37Z","receivedAt":"2020-02-14T01:54:17Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Add a new step to the build to generate a safelist of git-config\nvariables which are appropriate to include in the output of\ngit-bugreport. New variables can be added to the safelist by annotating\ntheir documentation in Documentation/config with the \"annotate\" macro,\nwhich is a no-op in AsciiDoc and AsciiDoctor.\n\nSome configs are private in nature, and can contain remote URLs,\npasswords, or other sensitive information. In the event that a user\ndoesn't notice their information while reviewing a bugreport, that user\nmay leak their credentials to other individuals, mailing lists, or bug\ntracking tools inadvertently. Heuristic blocklisting of configuration\nkeys is imperfect and prone to false negatives; given the nature of the\ninformation which can be leaked, a safelist is more reliable.\n\nHowever, it's possible that in some situations, an organization may be\nless concerned with privacy of things like remote URLs and branch names,\nand more concerned with ease of diagnosis for their support staff. In\nthose cases, it may make more sense for that organization to modify the\ncode to use a blocklist. To that end, we should try to mark configs which\nare definitely safe, and configs which are definitely unsafe, and leave\nblank configs which are somewhere in between. To mark a config as safe,\nadd \"annotate:bugreport[include]\" to the corresponding line in the\nconfig documentation; to mark it as unsafe, add\n\"annotate:bugreport[exclude]\" instead.\n\nGenerating bugreport-config-safelist.h at build time by grepping the\ndocumentation for this new macro helps us prevent staleness. The macro\nitself is a no-op and should not alter the appearance of the\ndocumentation in either AsciiDoc or AsciiDoctor, confirmable by running:\n\n  cd Documentation\n  ./doc-diff --asciidoctor HEAD^ HEAD\n  ./doc-diff --asciidoc HEAD^ HEAD\n\nDiffing the rendered HTML shows that only inline comments were added,\nwhich shouldn't be a problem.\n\nAdditionally, add annotations to the sendemail config documentation in\norder to demonstrate a proof of concept.\n\nHelped-by: Martin Ågren <martin.agren@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                              |  1 +\n Documentation/asciidoc.conf             |  9 ++++\n Documentation/asciidoctor-extensions.rb |  7 ++++\n Documentation/config/sendemail.txt      | 56 ++++++++++++-------------\n Makefile                                |  7 ++++\n generate-bugreport-config-safelist.sh   | 18 ++++++++\n 6 files changed, 70 insertions(+), 28 deletions(-)\n create mode 100755 generate-bugreport-config-safelist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex d89bf9e11e..bd2f49b996 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -192,6 +192,7 @@\n /gitweb/static/gitweb.min.*\n /config-list.h\n /command-list.h\n+/bugreport-config-safelist.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\nindex 8fc4b67081..663e06481f 100644\n--- a/Documentation/asciidoc.conf\n+++ b/Documentation/asciidoc.conf\n@@ -6,9 +6,14 @@\n #\n # Show Git link as: <command>(<section>); if section is defined, else just show\n # the command.\n+#\n+# The annotate macro does nothing as far as rendering is\n+# concerned -- we just grep for it in the sources to populate\n+# things like the bugreport safelist.\n \n [macros]\n (?su)[\\\\]?(?P<name>linkgit):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n+(?su)[\\\\]?(?P<name>annotate):(?P<target>\\S*?)\\[(?P<attrlist>.*?)\\]=\n \n [attributes]\n asterisk=&#42;\n@@ -28,6 +33,8 @@ ifdef::backend-docbook[]\n {0#<citerefentry>}\n {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n {0#</citerefentry>}\n+[annotate-inlinemacro]\n+{0#}\n endif::backend-docbook[]\n \n ifdef::backend-docbook[]\n@@ -94,4 +101,6 @@ ifdef::backend-xhtml11[]\n git-relative-html-prefix=\n [linkgit-inlinemacro]\n <a href=\"{git-relative-html-prefix}{target}.html\">{target}{0?({0})}</a>\n+[annotate-inlinemacro]\n+<!-- -->\n endif::backend-xhtml11[]\ndiff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb\nindex d906a00803..03c80af0e5 100644\n--- a/Documentation/asciidoctor-extensions.rb\n+++ b/Documentation/asciidoctor-extensions.rb\n@@ -39,10 +39,17 @@ module Git\n         output\n       end\n     end\n+\n+    class AnnotateProcessor < Asciidoctor::Extensions::InlineMacroProcessor\n+      def process(parent, target, attrs)\n+        \"\"\n+      end\n+    end\n   end\n end\n \n Asciidoctor::Extensions.register do\n   inline_macro Git::Documentation::LinkGitProcessor, :linkgit\n   postprocessor Git::Documentation::DocumentPostProcessor\n+  inline_macro Git::Documentation::AnnotateProcessor, :annotate\n end\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 0006faf800..fe27473e44 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -4,7 +4,7 @@ sendemail.identity::\n \tvalues in the 'sendemail' section. The default identity is\n \tthe value of `sendemail.identity`.\n \n-sendemail.smtpEncryption::\n+sendemail.smtpEncryption annotate:bugreport[include] ::\n \tSee linkgit:git-send-email[1] for description.  Note that this\n \tsetting is not subject to the 'identity' mechanism.\n \n@@ -15,7 +15,7 @@ sendemail.smtpsslcertpath::\n \tPath to ca-certificates (either a directory or a single file).\n \tSet it to an empty string to disable certificate verification.\n \n-sendemail.<identity>.*::\n+sendemail.<identity>.* annotate:bugreport[exclude] ::\n \tIdentity-specific versions of the 'sendemail.*' parameters\n \tfound below, taking precedence over those when this\n \tidentity is selected, through either the command-line or\n@@ -23,41 +23,41 @@ sendemail.<identity>.*::\n \n sendemail.aliasesFile::\n sendemail.aliasFileType::\n-sendemail.annotate::\n-sendemail.bcc::\n-sendemail.cc::\n-sendemail.ccCmd::\n-sendemail.chainReplyTo::\n-sendemail.confirm::\n-sendemail.envelopeSender::\n-sendemail.from::\n-sendemail.multiEdit::\n-sendemail.signedoffbycc::\n-sendemail.smtpPass::\n-sendemail.suppresscc::\n-sendemail.suppressFrom::\n-sendemail.to::\n-sendemail.tocmd::\n-sendemail.smtpDomain::\n-sendemail.smtpServer::\n-sendemail.smtpServerPort::\n-sendemail.smtpServerOption::\n-sendemail.smtpUser::\n-sendemail.thread::\n-sendemail.transferEncoding::\n-sendemail.validate::\n-sendemail.xmailer::\n+sendemail.annotate annotate:bugreport[include] ::\n+sendemail.bcc annotate:bugreport[include] ::\n+sendemail.cc annotate:bugreport[include] ::\n+sendemail.ccCmd annotate:bugreport[include] ::\n+sendemail.chainReplyTo annotate:bugreport[include] ::\n+sendemail.confirm annotate:bugreport[include] ::\n+sendemail.envelopeSender annotate:bugreport[include] ::\n+sendemail.from annotate:bugreport[include] ::\n+sendemail.multiEdit annotate:bugreport[include] ::\n+sendemail.signedoffbycc annotate:bugreport[include] ::\n+sendemail.smtpPass annotate:bugreport[exclude] ::\n+sendemail.suppresscc annotate:bugreport[include] ::\n+sendemail.suppressFrom annotate:bugreport[include] ::\n+sendemail.to annotate:bugreport[include] ::\n+sendemail.tocmd annotate:bugreport[include] ::\n+sendemail.smtpDomain annotate:bugreport[include] ::\n+sendemail.smtpServer annotate:bugreport[include] ::\n+sendemail.smtpServerPort annotate:bugreport[include] ::\n+sendemail.smtpServerOption annotate:bugreport[include] ::\n+sendemail.smtpUser annotate:bugreport[exclude] ::\n+sendemail.thread annotate:bugreport[include] ::\n+sendemail.transferEncoding annotate:bugreport[include] ::\n+sendemail.validate annotate:bugreport[include] ::\n+sendemail.xmailer annotate:bugreport[include] ::\n \tSee linkgit:git-send-email[1] for description.\n \n sendemail.signedoffcc (deprecated)::\n \tDeprecated alias for `sendemail.signedoffbycc`.\n \n-sendemail.smtpBatchSize::\n+sendemail.smtpBatchSize annotate:bugreport[include] ::\n \tNumber of messages to be sent per connection, after that a relogin\n \twill happen.  If the value is 0 or undefined, send all messages in\n \tone connection.\n \tSee also the `--batch-size` option of linkgit:git-send-email[1].\n \n-sendemail.smtpReloginDelay::\n+sendemail.smtpReloginDelay annotate:bugreport[include] ::\n \tSeconds wait before reconnecting to smtp server.\n \tSee also the `--relogin-delay` option of linkgit:git-send-email[1].\ndiff --git a/Makefile b/Makefile\nindex a01a050aa3..2bc9f112ea 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -817,6 +817,7 @@ VCSSVN_LIB = vcs-svn/lib.a\n \n GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n+GENERATED_H += bugreport-config-safelist.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n \t$(FIND) . \\\n@@ -2163,6 +2164,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\tcommand-list.txt >$@+ && mv $@+ $@\n \n+bugreport-config-safelist.h: generate-bugreport-config-safelist.sh\n+\n+bugreport-config-safelist.h: Documentation/config/*.txt\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\ndiff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh\nnew file mode 100755\nindex 0000000000..2794a8ae77\n--- /dev/null\n+++ b/generate-bugreport-config-safelist.sh\n@@ -0,0 +1,18 @@\n+#!/bin/sh\n+\n+cat <<EOF\n+/* Automatically generated by bugreport-generate-config-safelist.sh */\n+\n+\n+static const char *bugreport_config_safelist[] = {\n+EOF\n+\n+# cat all regular files in Documentation/config\n+find Documentation/config -type f -exec cat {} \\; |\n+# print the command name which matches the annotate-bugreport macro\n+sed -n 's/^\\([^[:blank:]]*\\)[[:blank:]]\\{1,\\}annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p' \\\n+\t| sort\n+\n+cat <<EOF\n+};\n+EOF\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391726","messageId":"20200214015343.201946-11-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 10/15] bugreport: add config values from safelist","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:38Z","receivedAt":"2020-02-14T01:54:19Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach bugreport to gather the values of config options which are present\nin 'bugreport-config-safelist.h', and show their origin scope.\n\nMany config options are sensitive, and many Git add-ons use config\noptions which git-core does not know about; it is better only to gather\nconfig options which we know to be safe, rather than excluding options\nwhich we know to be unsafe.\n\nRather than including the path to someone's config, which can reveal\nfilesystem layout and project names, just name the scope (e.g. system,\nglobal, local) of the config source.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n Makefile                        |  2 ++\n bugreport.c                     | 34 +++++++++++++++++++++++++++++++++\n 3 files changed, 37 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 23265b0d74..4e9171d1bd 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -30,6 +30,7 @@ The following information is captured automatically:\n  - Compiler-specific info string\n  - 'git remote-https --build-info'\n  - $SHELL\n+ - Selected config values\n \n OPTIONS\n -------\ndiff --git a/Makefile b/Makefile\nindex 2bc9f112ea..7b139230ae 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2131,6 +2131,8 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n+bugreport.sp bugreport.s bugreport.o: bugreport-config-safelist.h\n+\n builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\ndiff --git a/bugreport.c b/bugreport.c\nindex c1475601bf..1a9430a857 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -6,6 +6,9 @@\n #include \"help.h\"\n #include \"compat/compiler.h\"\n #include \"run-command.h\"\n+#include \"config.h\"\n+#include \"bugreport-config-safelist.h\"\n+#include \"khash.h\"\n \n static void get_git_remote_https_version_info(struct strbuf *version_info)\n {\n@@ -52,6 +55,29 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_complete_line(sys_info);\n }\n \n+static void get_safelisted_config(struct strbuf *config_info)\n+{\n+\tsize_t idx;\n+\tstruct string_list_item *it = NULL;\n+\tstruct key_value_info *kv_info = NULL;\n+\n+\tfor (idx = 0; idx < ARRAY_SIZE(bugreport_config_safelist); idx++) {\n+\t\tconst struct string_list *list =\n+\t\t\tgit_config_get_value_multi(bugreport_config_safelist[idx]);\n+\n+\t\tif (!list)\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_addf(config_info, \"%s:\\n\", bugreport_config_safelist[idx]);\n+\t\tfor_each_string_list_item(it, list) {\n+\t\t\tkv_info = it->util;\n+\t\t\tstrbuf_addf(config_info, \"  %s (%s)\\n\", it->string,\n+\t\t\t\t    kv_info ? config_scope_name(kv_info->scope)\n+\t\t\t\t\t    : \"source unknown\");\n+\t\t}\n+\t}\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -94,6 +120,7 @@ int cmd_main(int argc, const char **argv)\n \tchar *option_output = NULL;\n \tchar *option_suffix = \"%F-%H%M\";\n \tstruct stat statbuf;\n+\tint nongit_ok = 0;\n \n \tconst struct option bugreport_options[] = {\n \t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n@@ -102,6 +129,10 @@ int cmd_main(int argc, const char **argv)\n \t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n \t\tOPT_END()\n \t};\n+\n+\t/* Prerequisite for hooks and config checks */\n+\tsetup_git_directory_gently(&nongit_ok);\n+\n \targc = parse_options(argc, argv, \"\", bugreport_options,\n \t\t\t     bugreport_usage, 0);\n \n@@ -132,6 +163,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"System Info\");\n \tget_system_info(&buffer);\n \n+\tget_header(&buffer, \"Safelisted Config Info\");\n+\tget_safelisted_config(&buffer);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391727","messageId":"20200214015343.201946-12-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 11/15] bugreport: collect list of populated hooks","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:39Z","receivedAt":"2020-02-14T01:54:20Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Occasionally a failure a user is seeing may be related to a specific\nhook which is being run, perhaps without the user realizing. While the\ncontents of hooks can be sensitive - containing user data or process\ninformation specific to the user's organization - simply knowing that a\nhook is being run at a certain stage can help us to understand whether\nsomething is going wrong.\n\nWithout a definitive list of hook names within the code, we compile our\nown list from the documentation. This is likely prone to bitrot. To\nreduce the amount of code humans need to read, we turn the list into a\nstring_list and iterate over it (as we are calling the same find_hook\noperation on each string). However, since bugreport should primarily be\ncalled by the user, the performance loss from massaging the string\nseems acceptable.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 53 +++++++++++++++++++++++++++++++++\n 2 files changed, 54 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 4e9171d1bd..779c9c7fd9 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -31,6 +31,7 @@ The following information is captured automatically:\n  - 'git remote-https --build-info'\n  - $SHELL\n  - Selected config values\n+ - A list of enabled hooks\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 1a9430a857..7e6147a935 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -9,6 +9,7 @@\n #include \"config.h\"\n #include \"bugreport-config-safelist.h\"\n #include \"khash.h\"\n+#include \"run-command.h\"\n \n static void get_git_remote_https_version_info(struct strbuf *version_info)\n {\n@@ -78,6 +79,55 @@ static void get_safelisted_config(struct strbuf *config_info)\n \t}\n }\n \n+static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n+{\n+\t/*\n+\t * Doesn't look like there is a list of all possible hooks; so below is\n+\t * a transcription of `git help hooks`.\n+\t */\n+\tconst char *hooks = \"applypatch-msg,\"\n+\t\t\t    \"pre-applypatch,\"\n+\t\t\t    \"post-applypatch,\"\n+\t\t\t    \"pre-commit,\"\n+\t\t\t    \"pre-merge-commit,\"\n+\t\t\t    \"prepare-commit-msg,\"\n+\t\t\t    \"commit-msg,\"\n+\t\t\t    \"post-commit,\"\n+\t\t\t    \"pre-rebase,\"\n+\t\t\t    \"post-checkout,\"\n+\t\t\t    \"post-merge,\"\n+\t\t\t    \"pre-push,\"\n+\t\t\t    \"pre-receive,\"\n+\t\t\t    \"update,\"\n+\t\t\t    \"post-receive,\"\n+\t\t\t    \"post-update,\"\n+\t\t\t    \"push-to-checkout,\"\n+\t\t\t    \"pre-auto-gc,\"\n+\t\t\t    \"post-rewrite,\"\n+\t\t\t    \"sendemail-validate,\"\n+\t\t\t    \"fsmonitor-watchman,\"\n+\t\t\t    \"p4-pre-submit,\"\n+\t\t\t    \"post-index-changex\";\n+\tstruct string_list hooks_list = STRING_LIST_INIT_DUP;\n+\tstruct string_list_item *iter = NULL;\n+\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(hook_info,\n+\t\t\t\"not run from a git repository - no hooks to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstring_list_split(&hooks_list, hooks, ',', -1);\n+\n+\tfor_each_string_list_item(iter, &hooks_list) {\n+\t\tif (find_hook(iter->string)) {\n+\t\t\tstrbuf_addstr(hook_info, iter->string);\n+\t\t\tstrbuf_complete_line(hook_info);\n+\t\t}\n+\t}\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -166,6 +216,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Safelisted Config Info\");\n \tget_safelisted_config(&buffer);\n \n+\tget_header(&buffer, \"Enabled Hooks\");\n+\tget_populated_hooks(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391728","messageId":"20200214015343.201946-9-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 08/15] bugreport: include user interactive shell","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:36Z","receivedAt":"2020-02-14T01:54:22Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It's possible a user may complain about the way that Git interacts with\ntheir interactive shell, e.g. autocompletion or shell prompt. In that\ncase, it's useful for us to know which shell they're using\ninteractively.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt | 1 +\n bugreport.c                     | 5 +++++\n 2 files changed, 6 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 33df4dec7f..23265b0d74 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -29,6 +29,7 @@ The following information is captured automatically:\n  - uname sysname, release, version, and machine strings\n  - Compiler-specific info string\n  - 'git remote-https --build-info'\n+ - $SHELL\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex bfdff33368..c1475601bf 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -21,6 +21,7 @@ static void get_git_remote_https_version_info(struct strbuf *version_info)\n static void get_system_info(struct strbuf *sys_info)\n {\n \tstruct utsname uname_info;\n+\tchar *shell = NULL;\n \n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, \"git version:\\n\");\n@@ -42,6 +43,10 @@ static void get_system_info(struct strbuf *sys_info)\n \tget_compiler_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n \n+\tshell = getenv(\"SHELL\");\n+\tstrbuf_addf(sys_info, \"$SHELL (typically, interactive shell): %s\\n\",\n+\t\t    shell ? shell : \"<unset>\");\n+\n \tstrbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n \tget_git_remote_https_version_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391729","messageId":"20200214015343.201946-13-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 12/15] bugreport: count loose objects","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:40Z","receivedAt":"2020-02-14T01:54:23Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The number of unpacked objects in a user's repository may help us\nunderstand the root of the problem they're seeing, especially if a\ncommand is running unusually slowly.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 52 +++++++++++++++++++++++++++++++++\n 2 files changed, 53 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 779c9c7fd9..7e1ed44cb4 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -32,6 +32,7 @@ The following information is captured automatically:\n  - $SHELL\n  - Selected config values\n  - A list of enabled hooks\n+ - The number of loose objects in the repository\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 7e6147a935..f5201ce416 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -10,6 +10,7 @@\n #include \"bugreport-config-safelist.h\"\n #include \"khash.h\"\n #include \"run-command.h\"\n+#include \"object-store.h\"\n \n static void get_git_remote_https_version_info(struct strbuf *version_info)\n {\n@@ -128,6 +129,54 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n \t}\n }\n \n+static int loose_object_cb(const struct object_id *oid, const char *path,\n+\t\t\t   void *data) {\n+\tint *loose_object_count = data;\n+\n+\tif (loose_object_count) {\n+\t\t(*loose_object_count)++;\n+\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {\n+\n+\tint local_loose_object_count = 0, total_loose_object_count = 0;\n+\tint local_count_questionable = 0, total_count_questionable = 0;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(obj_info,\n+\t\t\t\"not run from a git repository - no objects to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tlocal_count_questionable = for_each_loose_object(\n+\t\t\t\t\tloose_object_cb,\n+\t\t\t\t\t&local_loose_object_count,\n+\t\t\t\t\tFOR_EACH_OBJECT_LOCAL_ONLY);\n+\n+\ttotal_count_questionable = for_each_loose_object(\n+\t\t\t\t\tloose_object_cb,\n+\t\t\t\t\t&total_loose_object_count,\n+\t\t\t\t\t0);\n+\n+\tstrbuf_addf(obj_info, \"%d local loose objects%s\\n\",\n+\t\t    local_loose_object_count,\n+\t\t    local_count_questionable ? \" (problem during count)\" : \"\");\n+\n+\tstrbuf_addf(obj_info, \"%d alternate loose objects%s\\n\",\n+\t\t    total_loose_object_count - local_loose_object_count,\n+\t\t    (local_count_questionable || total_count_questionable)\n+\t\t\t? \" (problem during count)\"\n+\t\t\t: \"\");\n+\n+\tstrbuf_addf(obj_info, \"%d total loose objects%s\\n\",\n+\t\t    total_loose_object_count,\n+\t\t    total_count_questionable ? \" (problem during count)\" : \"\");\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -219,6 +268,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Enabled Hooks\");\n \tget_populated_hooks(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Loose Object Counts\");\n+\tget_loose_object_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391730","messageId":"20200214015343.201946-14-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 13/15] bugreport: add packed object summary","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:41Z","receivedAt":"2020-02-14T01:54:24Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Alongside the loose object counts, it can be useful to show the number\nof packs and packed objects. This way we can check whether the repo has\nan appropriate ratio of packed to loose objects to help determine\nwhether it's behaving correctly.\n\nAdd a utility to easily traverse all packfiles in a given repository.\nUse it in packfile.c and remove a redundant call to\nprepare_packed_git(), which is already called in get_all_packs().\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 30 ++++++++++++++++++++++++++++++\n object-store.h                  |  6 ++++++\n packfile.c                      |  3 +--\n 4 files changed, 38 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 7e1ed44cb4..309b34fc42 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -33,6 +33,7 @@ The following information is captured automatically:\n  - Selected config values\n  - A list of enabled hooks\n  - The number of loose objects in the repository\n+ - The number of packs and packed objects in the repository\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex f5201ce416..580de13ddc 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -177,6 +177,33 @@ static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {\n \t\t    total_count_questionable ? \" (problem during count)\" : \"\");\n }\n \n+static void get_packed_object_summary(struct strbuf *obj_info, int nongit)\n+{\n+\tstruct packed_git *pack = NULL;\n+\tint pack_count = 0;\n+\tint object_count = 0;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(obj_info,\n+\t\t\t\"not run from a git repository - no objects to show\\n\");\n+\t\treturn;\n+\t}\n+\n+\tfor_each_pack(the_repository, pack) {\n+\t\tpack_count++;\n+\t\t/*\n+\t\t * To accurately count how many objects are packed, look inside\n+\t\t * the packfile's index.\n+\t\t */\n+\t\topen_pack_index(pack);\n+\t\tobject_count += pack->num_objects;\n+\t}\n+\n+\tstrbuf_addf(obj_info, \"%d total packs (%d objects)\\n\", pack_count,\n+\t\t    object_count);\n+\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -271,6 +298,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Loose Object Counts\");\n \tget_loose_object_summary(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Packed Object Summary\");\n+\tget_packed_object_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\ndiff --git a/object-store.h b/object-store.h\nindex 55ee639350..518c73469d 100644\n--- a/object-store.h\n+++ b/object-store.h\n@@ -6,6 +6,7 @@\n #include \"list.h\"\n #include \"sha1-array.h\"\n #include \"strbuf.h\"\n+#include \"packfile.h\"\n \n struct object_directory {\n \tstruct object_directory *next;\n@@ -403,4 +404,9 @@ int for_each_object_in_pack(struct packed_git *p,\n int for_each_packed_object(each_packed_object_fn, void *,\n \t\t\t   enum for_each_object_flags flags);\n \n+#define for_each_pack(repo, pack) \t\t\\\n+\t\tfor (pack = get_all_packs(repo);\\\n+\t\t     pack;\t\t\t\\\n+\t\t     pack = pack->next)\n+\n #endif /* OBJECT_STORE_H */\ndiff --git a/packfile.c b/packfile.c\nindex 7e7c04e4d8..6873827fb5 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -2061,8 +2061,7 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,\n \tint r = 0;\n \tint pack_errors = 0;\n \n-\tprepare_packed_git(the_repository);\n-\tfor (p = get_all_packs(the_repository); p; p = p->next) {\n+\tfor_each_pack(the_repository, p) {\n \t\tif ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)\n \t\t\tcontinue;\n \t\tif ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391731","messageId":"20200214015343.201946-8-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 07/15] bugreport: add git-remote-https version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:35Z","receivedAt":"2020-02-14T01:54:26Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"It's possible for git-remote-curl to be built separately from git; in that\ncase we want to know what version of cURL is used by git-remote-curl, not\nnecessarily which version was present at git-bugreport's build time.\nSo instead, ask git-remote-curl for the version information it knows\nabout.\n\nToday, \"git-remote-http\" and \"git-remote-https\" are aliased to\n\"git-remote-curl\"; but in case we rely on a different library than cURL\nin the future, let's not explicitly reference cURL from bugreport.\n\nFor longevity purposes, invoke the alias \"git-remote-https\" instead of\n\"git-remote-http\".\n\nSince it could have been built at a different time, also report the\nversion and built-from commit of git-remote-curl alongside the cURL info.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 16 ++++++++++++++++\n remote-curl.c                   |  8 ++++++++\n 3 files changed, 25 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 8bbc4c960c..33df4dec7f 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -28,6 +28,7 @@ The following information is captured automatically:\n  - 'git version --build-options'\n  - uname sysname, release, version, and machine strings\n  - Compiler-specific info string\n+ - 'git remote-https --build-info'\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 4f9101caeb..bfdff33368 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -5,6 +5,18 @@\n #include \"time.h\"\n #include \"help.h\"\n #include \"compat/compiler.h\"\n+#include \"run-command.h\"\n+\n+static void get_git_remote_https_version_info(struct strbuf *version_info)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\targv_array_push(&cp.args, \"git\");\n+\targv_array_push(&cp.args, \"remote-https\");\n+\targv_array_push(&cp.args, \"--build-info\");\n+\tif (capture_command(&cp, version_info, 0))\n+\t    strbuf_addstr(version_info, \"'git-remote-https --build-info' not supported\\n\");\n+}\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -29,6 +41,10 @@ static void get_system_info(struct strbuf *sys_info)\n \tstrbuf_addstr(sys_info, \"compiler info: \");\n \tget_compiler_info(sys_info);\n \tstrbuf_complete_line(sys_info);\n+\n+\tstrbuf_addstr(sys_info, \"git-remote-https --build-info:\\n\");\n+\tget_git_remote_https_version_info(sys_info);\n+\tstrbuf_complete_line(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 350d92a074..c590fbfae3 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -17,6 +17,7 @@\n #include \"protocol.h\"\n #include \"quote.h\"\n #include \"transport.h\"\n+#include \"version.h\"\n \n static struct remote *remote;\n /* always ends with a trailing slash */\n@@ -1374,6 +1375,13 @@ int cmd_main(int argc, const char **argv)\n \tstring_list_init(&options.deepen_not, 1);\n \tstring_list_init(&options.push_options, 1);\n \n+\tif (!strcmp(\"--build-info\", argv[1])) {\n+\t\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n+\t\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n+\t\tprintf(\"curl version: %s\\n\", curl_version());\n+\t\treturn 0;\n+\t}\n+\n \t/*\n \t * Just report \"remote-curl\" here (folding all the various aliases\n \t * (\"git-remote-http\", \"git-remote-https\", and etc.) here since they\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391732","messageId":"20200214015343.201946-15-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 14/15] bugreport: list contents of $OBJDIR/info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:42Z","receivedAt":"2020-02-14T01:54:28Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Miscellaneous information used about the object store can end up in\n.git/objects/info; this can help us understand what may be going on with\nthe object store when the user is reporting a bug. Otherwise, it could\nbe difficult to track down what is going wrong with an object which\nisn't kept locally to .git/objects/ or .git/objects/pack. Having some\nunderstanding of where the user's objects may be kept can save us some\nhops during the bug reporting process.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 54 +++++++++++++++++++++++++++++++++\n 2 files changed, 55 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 309b34fc42..a21d081616 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -34,6 +34,7 @@ The following information is captured automatically:\n  - A list of enabled hooks\n  - The number of loose objects in the repository\n  - The number of packs and packed objects in the repository\n+ - A list of the contents of .git/objects/info (or equivalent)\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 580de13ddc..1c67b55598 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -204,6 +204,57 @@ static void get_packed_object_summary(struct strbuf *obj_info, int nongit)\n \n }\n \n+static void list_contents_of_dir_recursively(struct strbuf *contents,\n+\t\t\t\t      \t     struct strbuf *dirpath)\n+{\n+\tstruct dirent *d;\n+\tDIR *dir;\n+\tsize_t path_len;\n+\n+\tdir = opendir(dirpath->buf);\n+\tif (!dir)\n+\t\treturn;\n+\n+\tstrbuf_complete(dirpath, '/');\n+\tpath_len = dirpath->len;\n+\n+\twhile ((d = readdir(dir))) {\n+\t\tif (!strcmp(d->d_name, \".\") || !strcmp(d->d_name, \"..\"))\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_addbuf(contents, dirpath);\n+\t\tstrbuf_addstr(contents, d->d_name);\n+\t\tstrbuf_complete_line(contents);\n+\n+\t\tif (d->d_type == DT_DIR) {\n+\t\t\tstrbuf_addstr(dirpath, d->d_name);\n+\t\t\tlist_contents_of_dir_recursively(contents, dirpath);\n+\t\t}\n+\t\tstrbuf_setlen(dirpath, path_len);\n+\t}\n+\n+\tclosedir(dir);\n+}\n+\n+static void get_object_info_summary(struct strbuf *obj_info, int nongit)\n+{\n+\tstruct strbuf dirpath = STRBUF_INIT;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(obj_info,\n+\t\t\t\"not run from a git repository - object info unavailable\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstrbuf_addstr(&dirpath, get_object_directory());\n+\tstrbuf_complete(&dirpath, '/');\n+\tstrbuf_addstr(&dirpath, \"info/\");\n+\n+\tlist_contents_of_dir_recursively(obj_info, &dirpath);\n+\n+\tstrbuf_release(&dirpath);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -301,6 +352,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Packed Object Summary\");\n \tget_packed_object_summary(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Object Info Summary\");\n+\tget_object_info_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391733","messageId":"20200214015343.201946-16-emilyshaffer@google.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"[PATCH v7 15/15] bugreport: summarize contents of alternates file","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T01:53:43Z","receivedAt":"2020-02-14T01:54:29Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"In some cases, it could be that the user is having a problem with an\nobject which isn't present in their normal object directory. We can get\na hint that that might be the case by examining the list of alternates\nwhere their object may be stored instead. Since paths to alternates may\nbe sensitive, we'll instead count how many alternates have been\nspecified and note how many of them exist or are broken.\n\nWhile object-cache.h describes a function \"foreach_alt_odb()\", this\nfunction does not provide information on broken alternates, which are\nskipped over in \"link_alt_odb_entry()\". Since the goal is to identify\nmissing alternates, we can gather the contents of\n.git/objects/info/alternates manually.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 45 +++++++++++++++++++++++++++++++++\n 2 files changed, 46 insertions(+)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex a21d081616..e870900c80 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -35,6 +35,7 @@ The following information is captured automatically:\n  - The number of loose objects in the repository\n  - The number of packs and packed objects in the repository\n  - A list of the contents of .git/objects/info (or equivalent)\n+ - The number of valid and invalid alternates\n \n OPTIONS\n -------\ndiff --git a/bugreport.c b/bugreport.c\nindex 1c67b55598..3bc8cb3579 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -255,6 +255,48 @@ static void get_object_info_summary(struct strbuf *obj_info, int nongit)\n \tstrbuf_release(&dirpath);\n }\n \n+static void get_alternates_summary(struct strbuf *alternates_info, int nongit)\n+{\n+\tstruct strbuf alternates_path = STRBUF_INIT;\n+\tstruct strbuf alternate = STRBUF_INIT;\n+\tFILE *file;\n+\tsize_t exists = 0, broken = 0;\n+\n+\tif (nongit) {\n+\t\tstrbuf_addstr(alternates_info,\n+\t\t\t\"not run from a git repository - alternates unavailable\\n\");\n+\t\treturn;\n+\t}\n+\n+\tstrbuf_addstr(&alternates_path, get_object_directory());\n+\tstrbuf_complete(&alternates_path, '/');\n+\tstrbuf_addstr(&alternates_path, \"info/alternates\");\n+\n+\tfile = fopen(alternates_path.buf, \"r\");\n+\tif (!file) {\n+\t\tstrbuf_addstr(alternates_info, \"No alternates file found.\\n\");\n+\t\tstrbuf_release(&alternates_path);\n+\t\treturn;\n+\t}\n+\n+\twhile (strbuf_getline(&alternate, file) != EOF) {\n+\t\tif (!access(alternate.buf, F_OK))\n+\t\t\texists++;\n+\t\telse\n+\t\t\tbroken++;\n+\t}\n+\n+\tstrbuf_addf(alternates_info,\n+\t\t    \"%zd alternates found (%zd working, %zd broken)\\n\",\n+\t\t    exists + broken,\n+\t\t    exists,\n+\t\t    broken);\n+\n+\tfclose(file);\n+\tstrbuf_release(&alternate);\n+\tstrbuf_release(&alternates_path);\n+}\n+\n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n \tNULL\n@@ -355,6 +397,9 @@ int cmd_main(int argc, const char **argv)\n \tget_header(&buffer, \"Object Info Summary\");\n \tget_object_info_summary(&buffer, nongit_ok);\n \n+\tget_header(&buffer, \"Alternates\");\n+\tget_alternates_summary(&buffer, nongit_ok);\n+\n \treport = fopen_for_writing(report_path.buf);\n \n \tif (report == NULL) {\n-- \n2.25.0.265.gbab2e86ba0-goog\n\n"},{"id":"391768","messageId":"xmqq4kvtp0ca.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200214015343.201946-15-emilyshaffer@google.com","subject":"Re: [PATCH v7 14/15] bugreport: list contents of $OBJDIR/info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-14T17:04:05Z","receivedAt":"2020-02-14T17:04:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> Miscellaneous information used about the object store can end up in\n> .git/objects/info; this can help us understand what may be going on with\n> the object store when the user is reporting a bug. Otherwise, it could\n> be difficult to track down what is going wrong with an object which\n> isn't kept locally to .git/objects/ or .git/objects/pack. Having some\n> understanding of where the user's objects may be kept can save us some\n> hops during the bug reporting process.\n\nThis step seems to have a new whitespace breakage that did not exist\nin the previous round.\n"},{"id":"391772","messageId":"xmqqzhdlnksn.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200214015343.201946-4-emilyshaffer@google.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-14T17:25:12Z","receivedAt":"2020-02-14T17:25:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> +\tswitch (safe_create_leading_directories(report_path.buf)) {\n\nThis helper is about creating paths in the working tree and Git\nrepository, hence it has a call to adjust_shared_perm() which in\nturn calls get_shared_repo(), i.e. requiring a repository.\n\nI thought I read somewhere that this tool is meant to be usable\noutside a repository?  If that is not the case, then the use of this\nhelper is OK.  If not, we may want to make sure that it will stay to\nbe safe to use the helper (I think it happens to be OK right now,\nbut if the reason why the user is trying to run the tool is because\nthe user broke Git by writing garbage into .git/config, we may\ndie(\"your configuration file is broken\") before this helper returns).\n\nThanks.\n\n\n"},{"id":"391773","messageId":"xmqqv9o9nkh3.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200214015343.201946-1-emilyshaffer@google.com","subject":"Re: [PATCH v7 00/15] add git-bugreport tool","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-14T17:32:08Z","receivedAt":"2020-02-14T17:32:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n>    present(patch 9/15). This now uses POSIX character classes and {}\n>    notation instead of + and has been tested on OSX; I'd love to hear if\n\nI'd rather not to see unnecessary uses of POSIX character classes.\n\nThe interdiff of this step between the previous and this round looks\nto me more like \"I used it, just because POSIX says I *can* use it\",\nnot \"I did so because I needed to do, and it should be OK on POSIX\nplatforms.\"\n\nInstead of overly long\n\n's/^\\([^[:blank:]]*\\)[[:blank:]]\\{1,\\}annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p'\n\njust limiting ourselves to SP and saying\n\n's/^\\([^ ]*\\)  *annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p'\n\nwould keep the result much easier to read, I would think.\n\n"},{"id":"391801","messageId":"20200214220003.GL190927@google.com","threadId":"52442","inReplyTo":"xmqqv9o9nkh3.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 00/15] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-14T22:00:03Z","receivedAt":"2020-02-14T22:00:13Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Feb 14, 2020 at 09:32:08AM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> >    present(patch 9/15). This now uses POSIX character classes and {}\n> >    notation instead of + and has been tested on OSX; I'd love to hear if\n> \n> I'd rather not to see unnecessary uses of POSIX character classes.\n> \n> The interdiff of this step between the previous and this round looks\n> to me more like \"I used it, just because POSIX says I *can* use it\",\n> not \"I did so because I needed to do, and it should be OK on POSIX\n> platforms.\"\n> \n> Instead of overly long\n> \n> 's/^\\([^[:blank:]]*\\)[[:blank:]]\\{1,\\}annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p'\n> \n> just limiting ourselves to SP and saying\n> \n> 's/^\\([^ ]*\\)  *annotate:bugreport\\[include\\].* ::$/  \"\\1\",/p'\n> \n> would keep the result much easier to read, I would think.\n\nThat's fine by me. I find the [[:syntax:]] extremely ugly, but I was\nworried about whether that was more portable somehow. Your proposal\nseems fine to me.\n\n - Emily\n"},{"id":"391802","messageId":"xmqq5zg8ol7m.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200214220003.GL190927@google.com","subject":"Re: [PATCH v7 00/15] add git-bugreport tool","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-14T22:30:53Z","receivedAt":"2020-02-14T22:30:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> That's fine by me. I find the [[:syntax:]] extremely ugly,...\n\nFWIW, I find it so too.\n"},{"id":"391821","messageId":"20200215015729.GN190927@google.com","threadId":"52442","inReplyTo":"xmqqzhdlnksn.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-15T01:57:29Z","receivedAt":"2020-02-15T01:57:37Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Feb 14, 2020 at 09:25:12AM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > +\tswitch (safe_create_leading_directories(report_path.buf)) {\n> \n> This helper is about creating paths in the working tree and Git\n> repository,\n\nIt's also used by cmd_format_patch() with --output-directory specified,\nwhich is how I found it. My usual workflow is to run format-patch with\n-o ~/mailed-patches/topic/ specified so I don't clutter my repo, so I'm\nsurprised to hear the intent of safe_create_leading_directores() is for\npaths in the working tree or repo.\n\n> hence it has a call to adjust_shared_perm() which in\n> turn calls get_shared_repo(), i.e. requiring a repository.\n\nHmmm. I was able to run it pretty happily from a nongit dir:\n\n  emilyshaffer@podkayne:~$ tg bugreport -o other/very/deep/path/\n  Created new report at 'other/very/deep/path/git-bugreport-2020-02-14-1721.txt'.\n  emilyshaffer@podkayne:~$ cat other/very/deep/path/git-bugreport-2020-02-14-1721.txt\n  Thank you for filling out a Git bug report!\n\n> I thought I read somewhere that this tool is meant to be usable\n> outside a repository?  If that is not the case, then the use of this\n> helper is OK.  If not, we may want to make sure that it will stay to\n> be safe to use the helper (I think it happens to be OK right now,\n> but if the reason why the user is trying to run the tool is because\n> the user broke Git by writing garbage into .git/config, we may\n> die(\"your configuration file is broken\") before this helper returns).\n\nCan you explain a little more about what you mean? A broken local\n.git/config seems to be preventing git.c from dispatching the\n'bugreport' subcommand (lots of other Git commands are broken) at all -\nbreakpoints in cmd_main() right after the variable declarations are not\nbeing hit.\n\nWith junk in the .git/config, I can't run bugreport from within that\nrepo. With junk in ~/.gitconfig, I can't run bugreport anywhere.\n\n(To make the configs invalid, I leaned on my keyboard and added a line\n'garbaghe~*~$%)%)(@' to the bottom of the config file. Most commands\nterminate early with \"fatal: bad config line 37 in file .git/config\".)\n\nDo you mean there's some specific config that could be misconfigured and\nprevent that utility from working?\n\n - Emily\n"},{"id":"391832","messageId":"xmqq1rqvogif.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200215015729.GN190927@google.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-15T18:24:40Z","receivedAt":"2020-02-15T18:24:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> On Fri, Feb 14, 2020 at 09:25:12AM -0800, Junio C Hamano wrote:\n>> Emily Shaffer <emilyshaffer@google.com> writes:\n>> \n>> > +\tswitch (safe_create_leading_directories(report_path.buf)) {\n>> \n>> This helper is about creating paths in the working tree and Git\n>> repository,\n>\n> It's also used by cmd_format_patch() with --output-directory specified,\n> which is how I found it.\n\nAnd that is an example of a good use of this helper.  What will be\nwritten out there should be visible by the same people as those who\nhave access to the repository; get_shared_repo() and adjust_perm()\nbased on what the repository you are taking patches from is\nperfectly sensible.  And as it is format-patch, we know we have\nget_shared_repo() working, and we know which repository we are\nworking on.\n\nOutput directory for bugreport is on the same boat when we know the\nusers are producing a report on their use of Git within a\nrepository.  It is not clear if the tool is started without any\nrepository---it happens to do a random safe thing (i.e. I think\nget_shared_repo() gives PERM_UMASK, which tells adjust_perm() not to\ndo anything especial) right now, but there is no guarantee that we\nwill keep it working like that.  Somebody may come and demaind\nget_shared_perm() to die() when outside a repository, for example,\nand that would break the nice property that lets bugreport working\noutside a repository.\n\nI just wanted to make sure that somebody will be keeping an eye to\nremind those who propose such a change in the future.  A comment\nnear where get_shared_repo() happens may be something that can be\ndone with a minimum effort when code that depends on that property\nis introduced at the same time.\n\n>> I thought I read somewhere that this tool is meant to be usable\n>> outside a repository?  If that is not the case, then the use of this\n>> helper is OK.  If not, we may want to make sure that it will stay to\n>> be safe to use the helper (I think it happens to be OK right now,\n\nI am actually OK if we limit the use of this tool to \"use with a\nrepository that is not corrupt\", as coping with these kinds of\nbreakages that in the main Git executable we deem \"needs manual\nintervention\" inside a single process is too painful (it would have\nbeen easier to cope with these too if we stuck with a script that\ninvokes many discrete commands and acts on their errors, but that is\noptimizing for rare case and not recommended).  But we should tell\nusers about the limitation and encourage them to ask for help in non\nautomatable means.\n\nThanks.\n"},{"id":"392033","messageId":"20200218234628.GA1461@google.com","threadId":"52442","inReplyTo":"xmqq1rqvogif.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-18T23:46:28Z","receivedAt":"2020-02-18T23:46:36Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Sat, Feb 15, 2020 at 10:24:40AM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > On Fri, Feb 14, 2020 at 09:25:12AM -0800, Junio C Hamano wrote:\n> >> Emily Shaffer <emilyshaffer@google.com> writes:\n> >> \n> >> > +\tswitch (safe_create_leading_directories(report_path.buf)) {\n> >> \n> >> This helper is about creating paths in the working tree and Git\n> >> repository,\n> >\n> > It's also used by cmd_format_patch() with --output-directory specified,\n> > which is how I found it.\n> \n> And that is an example of a good use of this helper.  What will be\n> written out there should be visible by the same people as those who\n> have access to the repository; get_shared_repo() and adjust_perm()\n> based on what the repository you are taking patches from is\n> perfectly sensible.  And as it is format-patch, we know we have\n> get_shared_repo() working, and we know which repository we are\n> working on.\n> \n> Output directory for bugreport is on the same boat when we know the\n> users are producing a report on their use of Git within a\n> repository.  It is not clear if the tool is started without any\n> repository---it happens to do a random safe thing (i.e. I think\n> get_shared_repo() gives PERM_UMASK, which tells adjust_perm() not to\n> do anything especial) right now, but there is no guarantee that we\n> will keep it working like that.  Somebody may come and demaind\n> get_shared_perm() to die() when outside a repository, for example,\n> and that would break the nice property that lets bugreport working\n> outside a repository.\n\nHm, this would break the convention of the name of\nsafe_create_leading_directories() too though right? As I understood it,\n\"safe_foo\" in this codebase means \"this function will not die()\"?\n\n> \n> I just wanted to make sure that somebody will be keeping an eye to\n> remind those who propose such a change in the future.  A comment\n> near where get_shared_repo() happens may be something that can be\n> done with a minimum effort when code that depends on that property\n> is introduced at the same time.\n\nOk. I want to make sure I understand you right. I think you're saying,\n\"This is OK, except if someone changes get_shared_repo() it could break,\nso we need a way to warn someone that it could break.\" It sounds like\nyou suggested leaving a comment in the\nsafe_create_leading_directories() helper. My own preference is to write\na test so that it's explicit that we depend on that behavior, instead -\nit's easy to gloss over a comment or read a different part of the\ncodebase, but it's hard to ignore a breaking test. It'd be trivial to\nadd one, so I will in v8 - unless I misunderstood you.\n\n> \n> >> I thought I read somewhere that this tool is meant to be usable\n> >> outside a repository?  If that is not the case, then the use of this\n> >> helper is OK.  If not, we may want to make sure that it will stay to\n> >> be safe to use the helper (I think it happens to be OK right now,\n> \n> I am actually OK if we limit the use of this tool to \"use with a\n> repository that is not corrupt\", as coping with these kinds of\n> breakages that in the main Git executable we deem \"needs manual\n> intervention\" inside a single process is too painful (it would have\n> been easier to cope with these too if we stuck with a script that\n> invokes many discrete commands and acts on their errors, but that is\n> optimizing for rare case and not recommended).  But we should tell\n> users about the limitation and encourage them to ask for help in non\n> automatable means.\n\nI think you're saying, \"Mention this drawback in the manpage for\ngit-bugreport.\" Sounds like a good idea to me, so I'll add it for v8.\n\n - Emily\n"},{"id":"392034","messageId":"20200218235622.GB1461@google.com","threadId":"52442","inReplyTo":"20200218234628.GA1461@google.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-18T23:56:22Z","receivedAt":"2020-02-18T23:56:31Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 18, 2020 at 03:46:28PM -0800, Emily Shaffer wrote:\n> On Sat, Feb 15, 2020 at 10:24:40AM -0800, Junio C Hamano wrote:\n> > I am actually OK if we limit the use of this tool to \"use with a\n> > repository that is not corrupt\", as coping with these kinds of\n> > breakages that in the main Git executable we deem \"needs manual\n> > intervention\" inside a single process is too painful (it would have\n> > been easier to cope with these too if we stuck with a script that\n> > invokes many discrete commands and acts on their errors, but that is\n> > optimizing for rare case and not recommended).  But we should tell\n> > users about the limitation and encourage them to ask for help in non\n> > automatable means.\n> \n> I think you're saying, \"Mention this drawback in the manpage for\n> git-bugreport.\" Sounds like a good idea to me, so I'll add it for v8.\n\nI'm pretty unsure about how you wanted this to sound; rather than\nsending a v8 only to revise it a lot, I'll send the paragraph for\nwordsmithing beforehand. Is this what you meant?\n\n  This tool is invoked via the typical Git setup process, which means that in some\n  cases, it might not be able to launch - for example, if a relevant config file\n  is unreadable. In this kind of scenario, it may be helpful to manually gather\n  the kind of information listed above when manually asking for help.\n\n - Emily\n"},{"id":"392035","messageId":"20200218235943.GC1461@google.com","threadId":"52442","inReplyTo":"xmqq4kvtp0ca.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 14/15] bugreport: list contents of $OBJDIR/info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-18T23:59:43Z","receivedAt":"2020-02-18T23:59:50Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Feb 14, 2020 at 09:04:05AM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > Miscellaneous information used about the object store can end up in\n> > .git/objects/info; this can help us understand what may be going on with\n> > the object store when the user is reporting a bug. Otherwise, it could\n> > be difficult to track down what is going wrong with an object which\n> > isn't kept locally to .git/objects/ or .git/objects/pack. Having some\n> > understanding of where the user's objects may be kept can save us some\n> > hops during the bug reporting process.\n> \n> This step seems to have a new whitespace breakage that did not exist\n> in the previous round.\n\nHmph. I saw it warned at some point during the rebase-and-format-patch\nworkflow for v7 but thought I had quashed it. Very sorry.\n\n - Emily\n"},{"id":"392058","messageId":"nycvar.QRO.7.76.6.2002191515310.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20200214015343.201946-4-emilyshaffer@google.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-02-19T14:18:09Z","receivedAt":"2020-02-19T14:18:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 13 Feb 2020, Emily Shaffer wrote:\n\n> diff --git a/bugreport.c b/bugreport.c\n> new file mode 100644\n> index 0000000000..a9398e6a2a\n> --- /dev/null\n> +++ b/bugreport.c\n> @@ -0,0 +1,94 @@\n> +#include \"builtin.h\"\n> +#include \"parse-options.h\"\n> +#include \"stdio.h\"\n> +#include \"strbuf.h\"\n> +#include \"time.h\"\n> +\n> +static const char * const bugreport_usage[] = {\n> +\tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n> +\tNULL\n> +};\n> +\n> +static int get_bug_template(struct strbuf *template)\n> +{\n> +\tconst char template_text[] = N_(\n> +\"Thank you for filling out a Git bug report!\\n\"\n> +\"Please answer the following questions to help us understand your issue.\\n\"\n> +\"\\n\"\n> +\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n> +\"\\n\"\n> +\"What did you expect to happen? (Expected behavior)\\n\"\n> +\"\\n\"\n> +\"What happened instead? (Actual behavior)\\n\"\n> +\"\\n\"\n> +\"What's different between what you expected and what actually happened?\\n\"\n> +\"\\n\"\n> +\"Anything else you want to add:\\n\"\n> +\"\\n\"\n> +\"Please review the rest of the bug report below.\\n\"\n> +\"You can delete any lines you don't wish to share.\\n\");\n> +\n> +\tstrbuf_addstr(template, template_text);\n> +\treturn 0;\n> +}\n> +\n> +int cmd_main(int argc, const char **argv)\n> +{\n> +\tstruct strbuf buffer = STRBUF_INIT;\n> +\tstruct strbuf report_path = STRBUF_INIT;\n> +\tFILE *report;\n> +\ttime_t now = time(NULL);\n> +\tchar *option_output = NULL;\n> +\tchar *option_suffix = \"%F-%H%M\";\n> +\tstruct stat statbuf;\n> +\n> +\tconst struct option bugreport_options[] = {\n> +\t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n> +\t\t\t   N_(\"specify a destination for the bugreport file\")),\n> +\t\tOPT_STRING('s', \"suffix\", &option_suffix, N_(\"format\"),\n> +\t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n> +\t\tOPT_END()\n> +\t};\n> +\targc = parse_options(argc, argv, \"\", bugreport_options,\n> +\t\t\t     bugreport_usage, 0);\n> +\n> +\tif (option_output) {\n> +\t\tstrbuf_addstr(&report_path, option_output);\n> +\t\tstrbuf_complete(&report_path, '/');\n> +\t}\n> +\n> +\n> +\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n> +\tstrbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);\n> +\tstrbuf_addstr(&report_path, \".txt\");\n> +\n> +\tif (!stat(report_path.buf, &statbuf))\n> +\t\tdie(\"'%s' already exists\", report_path.buf);\n> +\n> +\tswitch (safe_create_leading_directories(report_path.buf)) {\n> +\tcase SCLD_OK:\n> +\tcase SCLD_EXISTS:\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tdie(_(\"could not create leading directories for '%s'\"),\n> +\t\t    report_path.buf);\n> +\t}\n> +\n> +\tget_bug_template(&buffer);\n> +\n> +\treport = fopen_for_writing(report_path.buf);\n> +\n> +\tif (report == NULL) {\n> +\t\tstrbuf_release(&report_path);\n> +\t\tdie(\"couldn't open '%s' for writing\", report_path.buf);\n> +\t}\n> +\n> +\tstrbuf_write(&buffer, report);\n> +\tfclose(report);\n> +\n> +\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"), report_path.buf);\n> +\n> +\tUNLEAK(buffer);\n> +\tUNLEAK(report_path);\n> +\treturn -launch_editor(report_path.buf, NULL, NULL);\n\nThis would be the first time (at least that _I_ know of) that we use `-`\nin this way. We seem to use `!!` a lot more often. And now I wonder\nwhether there is a reason for that `-` that I missed?\n\nCiao,\nDscho\n"},{"id":"392059","messageId":"nycvar.QRO.7.76.6.2002191521140.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20200214015343.201946-7-emilyshaffer@google.com","subject":"Re: [PATCH v7 06/15] bugreport: add compiler info","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-02-19T14:23:34Z","receivedAt":"2020-02-19T14:23:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 13 Feb 2020, Emily Shaffer wrote:\n\n> To help pinpoint the source of a regression, it is useful to know some\n> info about the compiler which the user's Git client was built with. By\n> adding a generic get_compiler_info() in 'compat/' we can choose which\n> relevant information to share per compiler; to get started, let's\n> demonstrate the version of glibc if the user built with 'gcc'.\n\nI agree with the need for the compiler information, but in the patch I\nonly see information about glibc being printed out. Shouldn't we use\n`__GNUC__` and `__GNUC_MINOR__` here?\n\nDon't get me wrong, the glibc version is good and all, but the compiler\ninformation might be even more crucial. Git for Windows had to hold back\ncompiling with GCC v8.x for a while, for example, because the stacksmasher\nwas broken. Similar issues are not unheard of, and could help pinpoint\ncompiler-related problems a lot quicker.\n\nThanks,\nDscho\n\n>\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  Documentation/git-bugreport.txt |  1 +\n>  bugreport.c                     |  5 +++++\n>  compat/compiler.h               | 24 ++++++++++++++++++++++++\n>  3 files changed, 30 insertions(+)\n>  create mode 100644 compat/compiler.h\n>\n> diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\n> index 4dd72c60f5..8bbc4c960c 100644\n> --- a/Documentation/git-bugreport.txt\n> +++ b/Documentation/git-bugreport.txt\n> @@ -27,6 +27,7 @@ The following information is captured automatically:\n>\n>   - 'git version --build-options'\n>   - uname sysname, release, version, and machine strings\n> + - Compiler-specific info string\n>\n>  OPTIONS\n>  -------\n> diff --git a/bugreport.c b/bugreport.c\n> index b76a1dfb2a..4f9101caeb 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -4,6 +4,7 @@\n>  #include \"strbuf.h\"\n>  #include \"time.h\"\n>  #include \"help.h\"\n> +#include \"compat/compiler.h\"\n>\n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n> @@ -24,6 +25,10 @@ static void get_system_info(struct strbuf *sys_info)\n>  \t\t\t    uname_info.release,\n>  \t\t\t    uname_info.version,\n>  \t\t\t    uname_info.machine);\n> +\n> +\tstrbuf_addstr(sys_info, \"compiler info: \");\n> +\tget_compiler_info(sys_info);\n> +\tstrbuf_complete_line(sys_info);\n>  }\n>\n>  static const char * const bugreport_usage[] = {\n> diff --git a/compat/compiler.h b/compat/compiler.h\n> new file mode 100644\n> index 0000000000..bda5098e1b\n> --- /dev/null\n> +++ b/compat/compiler.h\n> @@ -0,0 +1,24 @@\n> +#ifndef COMPILER_H\n> +#define COMPILER_H\n> +\n> +#include \"git-compat-util.h\"\n> +#include \"strbuf.h\"\n> +\n> +#ifdef __GLIBC__\n> +#include <gnu/libc-version.h>\n> +\n> +static inline void get_compiler_info(struct strbuf *info)\n> +{\n> +\tstrbuf_addf(info, \"glibc: %s\", gnu_get_libc_version());\n> +}\n> +\n> +#else\n> +\n> +static inline void get_compiler_info(struct strbuf *info)\n> +{\n> +\tstrbuf_addstr(info, \"get_compiler_info() not implemented\");\n> +}\n> +\n> +#endif\n> +\n> +#endif /* COMPILER_H */\n> --\n> 2.25.0.265.gbab2e86ba0-goog\n>\n>\n"},{"id":"392060","messageId":"nycvar.QRO.7.76.6.2002191524460.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20200214015343.201946-8-emilyshaffer@google.com","subject":"Re: [PATCH v7 07/15] bugreport: add git-remote-https version","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-02-19T14:28:35Z","receivedAt":"2020-02-19T14:28:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 13 Feb 2020, Emily Shaffer wrote:\n\n> diff --git a/bugreport.c b/bugreport.c\n> index 4f9101caeb..bfdff33368 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -5,6 +5,18 @@\n>  #include \"time.h\"\n>  #include \"help.h\"\n>  #include \"compat/compiler.h\"\n> +#include \"run-command.h\"\n> +\n> +static void get_git_remote_https_version_info(struct strbuf *version_info)\n> +{\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\n> +\targv_array_push(&cp.args, \"git\");\n> +\targv_array_push(&cp.args, \"remote-https\");\n> +\targv_array_push(&cp.args, \"--build-info\");\n> +\tif (capture_command(&cp, version_info, 0))\n\nLet's use RUN_GIT_CMD instead of adding `\"git\"` explicitly; It documents\nthat we're interested in a Git command, and if we ever build a\nsingle-binary version of Git (as some Git for Windows users already asked\nfor), it will make things easier.\n\n> +\t    strbuf_addstr(version_info, \"'git-remote-https --build-info' not supported\\n\");\n> +}\n>\n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n> diff --git a/remote-curl.c b/remote-curl.c\n> index 350d92a074..c590fbfae3 100644\n> --- a/remote-curl.c\n> +++ b/remote-curl.c\n> @@ -1374,6 +1375,13 @@ int cmd_main(int argc, const char **argv)\n>  \tstring_list_init(&options.deepen_not, 1);\n>  \tstring_list_init(&options.push_options, 1);\n>\n> +\tif (!strcmp(\"--build-info\", argv[1])) {\n\nThe context does not say this, but at this point, we already verified that\n`argc` is larger than 1. Good.\n\nAlso, in keeping with the existing code, we would need to use\n`--build-options` here (this is what `git version` calls the equivalent\nmode).\n\n_However_.\n\nI like your `--build-info` a lot more than `--build-options` (because the\nlatter is very misleading: the commit and the date of the build are not\n\"options\" at all).\n\nThanks,\nDscho\n\n> +\t\tprintf(\"git-http-fetch version: %s\\n\", git_version_string);\n> +\t\tprintf(\"built from commit: %s\\n\", git_built_from_commit_string);\n> +\t\tprintf(\"curl version: %s\\n\", curl_version());\n> +\t\treturn 0;\n> +\t}\n> +\n>  \t/*\n>  \t * Just report \"remote-curl\" here (folding all the various aliases\n>  \t * (\"git-remote-http\", \"git-remote-https\", and etc.) here since they\n> --\n> 2.25.0.265.gbab2e86ba0-goog\n>\n>\n"},{"id":"392072","messageId":"xmqq7e0ih5zr.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"nycvar.QRO.7.76.6.2002191515310.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-19T16:55:04Z","receivedAt":"2020-02-19T16:55:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> +int cmd_main(int argc, const char **argv)\n>> +{\n>> +...\n>> +\tif (report == NULL) {\n>> +\t\tstrbuf_release(&report_path);\n>> +\t\tdie(\"couldn't open '%s' for writing\", report_path.buf);\n>> +\t}\n>> +\n>> +\tstrbuf_write(&buffer, report);\n>> +\tfclose(report);\n>> +\n>> +\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"), report_path.buf);\n>> +\n>> +\tUNLEAK(buffer);\n>> +\tUNLEAK(report_path);\n>> +\treturn -launch_editor(report_path.buf, NULL, NULL);\n>\n> This would be the first time (at least that _I_ know of) that we use `-`\n> in this way. We seem to use `!!` a lot more often. And now I wonder\n> whether there is a reason for that `-` that I missed?\n\nIn general, our preferred way to report an error from API functions\nis to return a negative number and a success is reported by\nreturning zero.\n\nThe argument to exit(3), which the return value from the main()\nfunction essentially is, on the other hand, is expected to be a\nsmall non-negative integer.  As long as we are in tight control of\nthe range of the returned value from launch_editor() (i.e. it must\nreturn a small non-positive integer whose negation is suitable to be\nfed to exit(3)), the above is fine.\n\nThe idiom \"return !!fn();\" is to canonicalize the value to 0 or 1\nfor the caller who asked \"so, did fn() give us 0 or non-zero?\",\nwhich can also be used as the value given to exit(3), and could be\nmore appropriate under some conditions:\n\n - we MUST know launch_editor() returns zero if and only if it is\n   successful.\n\n - we do not have to be confident to be in tight control of the\n   range of the returned value from launch_editor() (e.g. it could\n   return a positive upon an error).\n\n - we MUST NOT care to differenciate different error codes returned\n   from launch_editor().  IOW, we must be fine to give the invoker\n   of the program only 0 (success) or 1 (unspecified failure).\n\nUse of \"return !!fn();\" that is not to give to exit(3) is probably\nmore common in our codebase.  See apply.c::try_create_file() and the\ncomment before the function about its possible return values for\nexample.\n"},{"id":"392121","messageId":"20200219215231.GA26221@google.com","threadId":"52442","inReplyTo":"xmqq7e0ih5zr.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-19T21:52:31Z","receivedAt":"2020-02-19T21:52:40Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Wed, Feb 19, 2020 at 08:55:04AM -0800, Junio C Hamano wrote:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> +int cmd_main(int argc, const char **argv)\n> >> +{\n> >> +...\n> >> +\tif (report == NULL) {\n> >> +\t\tstrbuf_release(&report_path);\n> >> +\t\tdie(\"couldn't open '%s' for writing\", report_path.buf);\n> >> +\t}\n> >> +\n> >> +\tstrbuf_write(&buffer, report);\n> >> +\tfclose(report);\n> >> +\n> >> +\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"), report_path.buf);\n> >> +\n> >> +\tUNLEAK(buffer);\n> >> +\tUNLEAK(report_path);\n> >> +\treturn -launch_editor(report_path.buf, NULL, NULL);\n> >\n> > This would be the first time (at least that _I_ know of) that we use `-`\n> > in this way. We seem to use `!!` a lot more often. And now I wonder\n> > whether there is a reason for that `-` that I missed?\n> \n> In general, our preferred way to report an error from API functions\n> is to return a negative number and a success is reported by\n> returning zero.\n> \n> The argument to exit(3), which the return value from the main()\n> function essentially is, on the other hand, is expected to be a\n> small non-negative integer.  As long as we are in tight control of\n> the range of the returned value from launch_editor() (i.e. it must\n> return a small non-positive integer whose negation is suitable to be\n> fed to exit(3)), the above is fine.\n> \n> The idiom \"return !!fn();\" is to canonicalize the value to 0 or 1\n> for the caller who asked \"so, did fn() give us 0 or non-zero?\",\n> which can also be used as the value given to exit(3), and could be\n> more appropriate under some conditions:\n\nIn editor.c, launch_editor() returns launch_specified_editor() without\naltering the return code.\n\n> \n>  - we MUST know launch_editor() returns zero if and only if it is\n>    successful.\n\nlaunch_specified_editor() has a handful of exit points, of three kinds:\n 1. return error(something)\n 2. raise(sigsomething)\n 3. return 0\n    a. when the editor process closed happily, but the user supplied\n       NULL instead of a buffer. That is, the user didn't want the\n       contents of the editor given back to them in a strbuf.\n    b. when the editor process closed happily and the user's supplied\n       buffer was filled with the file's contents with no issue.\n\nSo I think we can check \"yes\" here.\n\n> \n>  - we do not have to be confident to be in tight control of the\n>    range of the returned value from launch_editor() (e.g. it could\n>    return a positive upon an error).\n\nAccording to 'man 3 raise' (POSIX), raise() exits the current thread. If it\ncan't exit itself(?) it seems it returns \"nonzero for failure\". We've\nalso got a mingw_raise() in compat/mingw.h which could be used instead;\nthis one seems to return -1 or the result of raise(), presumably the one\nfrom the MSC runtime[1], which also returns \"a nonzero value\" if not\nsuccessful.\n\nSo it's true that we aren't confident that launch_editor() returns a\npositive or negative value.\n\n>  - we MUST NOT care to differenciate different error codes returned\n>    from launch_editor().  IOW, we must be fine to give the invoker\n>    of the program only 0 (success) or 1 (unspecified failure).\n\nThis part is a little sticking point for me; I think I'd rather give the\nuser some hint of what's broken than no hint at all, especially in this\nscenario, where it's conceivable someone could say \"I tried to run\n'git-bugreport' and it crashed, here is the return code and I have\nmanually collected some relevant info too\".\n\nThe uncertainty coming from raise() (POSIX and MSCR both) leads me to\nbelieve if I do want to return the error on exit, I should at least\ncheck the sign before I flip it. Anybody else have opinions?\n\n - Emily\n\n[1] https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/raise?view=vs-2019\n"},{"id":"392123","messageId":"xmqqtv3mcjpv.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200219215231.GA26221@google.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-19T22:09:48Z","receivedAt":"2020-02-19T22:09:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> launch_specified_editor() has a handful of exit points, of three kinds:\n>  1. return error(something)\n>  2. raise(sigsomething)\n>  3. return 0\n>     a. when the editor process closed happily, but the user supplied\n>        NULL instead of a buffer. That is, the user didn't want the\n>        contents of the editor given back to them in a strbuf.\n>     b. when the editor process closed happily and the user's supplied\n>        buffer was filled with the file's contents with no issue.\n>\n> So I think we can check \"yes\" here.\n\nHeh.  If we raised a signal to kill ourselves, then we won't be\nreturning a value from launch_editor() anyway.  That case won't\naffect the \"between returning negation or !!, which is more\nappropriate?\" discussion, I think.\n\n>>  - we MUST NOT care to differenciate different error codes returned\n>>    from launch_editor().  IOW, we must be fine to give the invoker\n>>    of the program only 0 (success) or 1 (unspecified failure).\n\nI actually think this holds for the codepath.  A failure from\nstart_command() returns error(), and finish_command() that waits for\nthe spawned editor process to complete yields the exit status from\nthe editor, but unless we re-raise the signal that killed the editor\nprocess to ourselves, we just turn any non-zero exit into \"return\nerror()\", so it is safe to say launch_editor() can return either 0\nor -1 and nothing else.  Would we later want to tell callers of\nlaunch_editor() how/why the editor session failed by returning\nsomething else?  I do not offhand think of any---we do not even\ndifferenciate between failure to start (e.g. misspelt command name\nfor the editor) and other failures WITH the return value and\nconsider it sufficient to tell the user with different error\nmessage right now.\n\nSo in practice returning -launch_editor() and !!launch_editor()\nwould not make any difference, I would think.\n\n"},{"id":"392124","messageId":"20200219222807.GB26221@google.com","threadId":"52442","inReplyTo":"nycvar.QRO.7.76.6.2002191524460.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v7 07/15] bugreport: add git-remote-https version","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-19T22:28:07Z","receivedAt":"2020-02-19T22:28:16Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Wed, Feb 19, 2020 at 03:28:35PM +0100, Johannes Schindelin wrote:\n> Hi Emily,\n> \n> On Thu, 13 Feb 2020, Emily Shaffer wrote:\n> \n> > diff --git a/bugreport.c b/bugreport.c\n> > index 4f9101caeb..bfdff33368 100644\n> > --- a/bugreport.c\n> > +++ b/bugreport.c\n> > @@ -5,6 +5,18 @@\n> >  #include \"time.h\"\n> >  #include \"help.h\"\n> >  #include \"compat/compiler.h\"\n> > +#include \"run-command.h\"\n> > +\n> > +static void get_git_remote_https_version_info(struct strbuf *version_info)\n> > +{\n> > +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> > +\n> > +\targv_array_push(&cp.args, \"git\");\n> > +\targv_array_push(&cp.args, \"remote-https\");\n> > +\targv_array_push(&cp.args, \"--build-info\");\n> > +\tif (capture_command(&cp, version_info, 0))\n> \n> Let's use RUN_GIT_CMD instead of adding `\"git\"` explicitly; It documents\n> that we're interested in a Git command, and if we ever build a\n> single-binary version of Git (as some Git for Windows users already asked\n> for), it will make things easier.\n\nHm. RUN_GIT_CMD is an argument used for the run_command_v_opt* family of\ncalls, but it seems that setting child_process.git_cmd has the same\neffect. Done.\n\n> \n> > +\t    strbuf_addstr(version_info, \"'git-remote-https --build-info' not supported\\n\");\n> > +}\n> >\n> >  static void get_system_info(struct strbuf *sys_info)\n> >  {\n> > diff --git a/remote-curl.c b/remote-curl.c\n> > index 350d92a074..c590fbfae3 100644\n> > --- a/remote-curl.c\n> > +++ b/remote-curl.c\n> > @@ -1374,6 +1375,13 @@ int cmd_main(int argc, const char **argv)\n> >  \tstring_list_init(&options.deepen_not, 1);\n> >  \tstring_list_init(&options.push_options, 1);\n> >\n> > +\tif (!strcmp(\"--build-info\", argv[1])) {\n> \n> The context does not say this, but at this point, we already verified that\n> `argc` is larger than 1. Good.\n> \n> Also, in keeping with the existing code, we would need to use\n> `--build-options` here (this is what `git version` calls the equivalent\n> mode).\n> \n> _However_.\n> \n> I like your `--build-info` a lot more than `--build-options` (because the\n> latter is very misleading: the commit and the date of the build are not\n> \"options\" at all).\n\nSure. Thanks for saying so.\n\n - Emily\n"},{"id":"392125","messageId":"xmqqpneacim1.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200219222807.GB26221@google.com","subject":"Re: [PATCH v7 07/15] bugreport: add git-remote-https version","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-19T22:33:42Z","receivedAt":"2020-02-19T22:33:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n>> Also, in keeping with the existing code, we would need to use\n>> `--build-options` here (this is what `git version` calls the equivalent\n>> mode).\n>> \n>> _However_.\n>> \n>> I like your `--build-info` a lot more than `--build-options` (because the\n>> latter is very misleading: the commit and the date of the build are not\n>> \"options\" at all).\n>\n> Sure. Thanks for saying so.\n\nI don't think anybody would mind introducing --build-info to \"git\nversion\" as a synonym and deprecate --build-options from it ;-)\n"},{"id":"392126","messageId":"20200219224547.GC26221@google.com","threadId":"52442","inReplyTo":"nycvar.QRO.7.76.6.2002191521140.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v7 06/15] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-19T22:45:47Z","receivedAt":"2020-02-19T22:45:54Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Wed, Feb 19, 2020 at 03:23:34PM +0100, Johannes Schindelin wrote:\n> Hi Emily,\n> \n> On Thu, 13 Feb 2020, Emily Shaffer wrote:\n> \n> > To help pinpoint the source of a regression, it is useful to know some\n> > info about the compiler which the user's Git client was built with. By\n> > adding a generic get_compiler_info() in 'compat/' we can choose which\n> > relevant information to share per compiler; to get started, let's\n> > demonstrate the version of glibc if the user built with 'gcc'.\n> \n> I agree with the need for the compiler information, but in the patch I\n> only see information about glibc being printed out. Shouldn't we use\n> `__GNUC__` and `__GNUC_MINOR__` here?\n> \n> Don't get me wrong, the glibc version is good and all, but the compiler\n> information might be even more crucial. Git for Windows had to hold back\n> compiling with GCC v8.x for a while, for example, because the stacksmasher\n> was broken. Similar issues are not unheard of, and could help pinpoint\n> compiler-related problems a lot quicker.\n\nHm, sure. Good point - thanks.\n\nThis does make me start to wonder, though - does it really make sense to\nhave ifdef-gated redefinitions of the whole get_compiler_info() method\nlike I do now? I wonder if it makes more sense to have only one\ndefinition, so we can write down everything we know regardless of which\npieces are put together. My thinking is something like this - what if I\nam using glibc, but not a GNU compiler? (The GNU docs on __GCC__\nindicate this is a situation that might occur - \"a non-GCC compiler that\nclaims to accept the GNU C dialects\") Is there some striking reason not\nto implement this compat command thusly instead:\n\n  #ifdef __GLIBC__\n  #include <gnu/libc-version.h>\n  #endif\n\n  static inline void get_compiler_info(struct strbuf *info)\n  {\n  \t#ifdef __GLIBC__\n\tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n\t#endif\n\n\t#ifdef __GNUC__\n\tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n\t#endif\n\n\t#ifdef _MSC_VER\n\tstrbuf_addf(info, \"msc runtime: %s\\n\", some_msc_info());\n\t#endif\n  }\n\nThe thinking being - this way if I decide to use, say, LLVM + glibc,\nthen I don't need to reimplement this command with all the glibc\ndiagnostics again. Or, if someone else already wrote diagnostics for\nLLVM with some other libc, then it even Just Works for me and my new\ncombination.\n\nThat said, I'm reasoning about these combinations of compilers and libcs\nand whatever else from an inexperienced viewpoint, so maybe this isn't\nnecessary?\n\n - Emily\n"},{"id":"392127","messageId":"20200219230659.GA79731@google.com","threadId":"52442","inReplyTo":"xmqqtv3mcjpv.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-19T23:06:59Z","receivedAt":"2020-02-19T23:07:08Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Wed, Feb 19, 2020 at 02:09:48PM -0800, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > launch_specified_editor() has a handful of exit points, of three kinds:\n> >  1. return error(something)\n> >  2. raise(sigsomething)\n> >  3. return 0\n> >     a. when the editor process closed happily, but the user supplied\n> >        NULL instead of a buffer. That is, the user didn't want the\n> >        contents of the editor given back to them in a strbuf.\n> >     b. when the editor process closed happily and the user's supplied\n> >        buffer was filled with the file's contents with no issue.\n> >\n> > So I think we can check \"yes\" here.\n> \n> Heh.  If we raised a signal to kill ourselves, then we won't be\n> returning a value from launch_editor() anyway.  That case won't\n> affect the \"between returning negation or !!, which is more\n> appropriate?\" discussion, I think.\n> \n> >>  - we MUST NOT care to differenciate different error codes returned\n> >>    from launch_editor().  IOW, we must be fine to give the invoker\n> >>    of the program only 0 (success) or 1 (unspecified failure).\n> \n> I actually think this holds for the codepath.  A failure from\n> start_command() returns error(), and finish_command() that waits for\n> the spawned editor process to complete yields the exit status from\n> the editor, but unless we re-raise the signal that killed the editor\n> process to ourselves, we just turn any non-zero exit into \"return\n> error()\", so it is safe to say launch_editor() can return either 0\n> or -1 and nothing else.  Would we later want to tell callers of\n> launch_editor() how/why the editor session failed by returning\n> something else?  I do not offhand think of any---we do not even\n> differenciate between failure to start (e.g. misspelt command name\n> for the editor) and other failures WITH the return value and\n> consider it sufficient to tell the user with different error\n> message right now.\n> \n> So in practice returning -launch_editor() and !!launch_editor()\n> would not make any difference, I would think.\n\nThen, let's do the least surprising thing. I'll switch it to !! for the\nnext reroll.\n"},{"id":"392128","messageId":"20200219231554.GB79731@google.com","threadId":"52442","inReplyTo":"20200218235622.GB1461@google.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-19T23:15:54Z","receivedAt":"2020-02-19T23:16:01Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Feb 18, 2020 at 03:56:22PM -0800, Emily Shaffer wrote:\n> On Tue, Feb 18, 2020 at 03:46:28PM -0800, Emily Shaffer wrote:\n> > On Sat, Feb 15, 2020 at 10:24:40AM -0800, Junio C Hamano wrote:\n> > > I am actually OK if we limit the use of this tool to \"use with a\n> > > repository that is not corrupt\", as coping with these kinds of\n> > > breakages that in the main Git executable we deem \"needs manual\n> > > intervention\" inside a single process is too painful (it would have\n> > > been easier to cope with these too if we stuck with a script that\n> > > invokes many discrete commands and acts on their errors, but that is\n> > > optimizing for rare case and not recommended).  But we should tell\n> > > users about the limitation and encourage them to ask for help in non\n> > > automatable means.\n> > \n> > I think you're saying, \"Mention this drawback in the manpage for\n> > git-bugreport.\" Sounds like a good idea to me, so I'll add it for v8.\n> \n> I'm pretty unsure about how you wanted this to sound; rather than\n> sending a v8 only to revise it a lot, I'll send the paragraph for\n> wordsmithing beforehand. Is this what you meant?\n> \n>   This tool is invoked via the typical Git setup process, which means that in some\n>   cases, it might not be able to launch - for example, if a relevant config file\n>   is unreadable. In this kind of scenario, it may be helpful to manually gather\n>   the kind of information listed above when manually asking for help.\n\nSince I saw lots of replies from Junio elsewhere in this thread, I'll\ntake the silence here as assent. v8 on its way momentarily.\n\n - Emily\n"},{"id":"392129","messageId":"xmqqlfoycg9p.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200219231554.GB79731@google.com","subject":"Re: [PATCH v7 03/15] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-19T23:24:18Z","receivedAt":"2020-02-19T23:24:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> On Tue, Feb 18, 2020 at 03:56:22PM -0800, Emily Shaffer wrote:\n>> On Tue, Feb 18, 2020 at 03:46:28PM -0800, Emily Shaffer wrote:\n>> > On Sat, Feb 15, 2020 at 10:24:40AM -0800, Junio C Hamano wrote:\n>> > > I am actually OK if we limit the use of this tool to \"use with a\n>> > > repository that is not corrupt\", as coping with these kinds of\n>> > > breakages that in the main Git executable we deem \"needs manual\n>> > > intervention\" inside a single process is too painful (it would have\n>> > > been easier to cope with these too if we stuck with a script that\n>> > > invokes many discrete commands and acts on their errors, but that is\n>> > > optimizing for rare case and not recommended).  But we should tell\n>> > > users about the limitation and encourage them to ask for help in non\n>> > > automatable means.\n>> > \n>> > I think you're saying, \"Mention this drawback in the manpage for\n>> > git-bugreport.\" Sounds like a good idea to me, so I'll add it for v8.\n>> \n>> I'm pretty unsure about how you wanted this to sound; rather than\n>> sending a v8 only to revise it a lot, I'll send the paragraph for\n>> wordsmithing beforehand. Is this what you meant?\n>> \n>>   This tool is invoked via the typical Git setup process, which means that in some\n>>   cases, it might not be able to launch - for example, if a relevant config file\n>>   is unreadable. In this kind of scenario, it may be helpful to manually gather\n>>   the kind of information listed above when manually asking for help.\n>\n> Since I saw lots of replies from Junio elsewhere in this thread, I'll\n> take the silence here as assent. v8 on its way momentarily.\n\nHeh, it's just I have too little time to allocate on this single\ntopic X-<.  Don't take silence as anything else.\n\n"},{"id":"392211","messageId":"nycvar.QRO.7.76.6.2002202306390.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20200219224547.GC26221@google.com","subject":"Re: [PATCH v7 06/15] bugreport: add compiler info","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-02-20T22:33:05Z","receivedAt":"2020-02-20T22:33:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Wed, 19 Feb 2020, Emily Shaffer wrote:\n\n>   #ifdef __GLIBC__\n>   #include <gnu/libc-version.h>\n>   #endif\n>\n>   static inline void get_compiler_info(struct strbuf *info)\n>   {\n>   \t#ifdef __GLIBC__\n> \tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n> \t#endif\n>\n> \t#ifdef __GNUC__\n> \tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n> \t#endif\n>\n> \t#ifdef _MSC_VER\n> \tstrbuf_addf(info, \"msc runtime: %s\\n\", some_msc_info());\n\nYou could do it this way right away:\n\n\tstrbuf_addf(info, \"MSVC version: %d.%d\\n\",\n\t\t    _MSC_VER / 100, _MSC_VER % 100);\n\nNote: this is _not_ the MSVC _runtime_ version, but really the compiler\nversion.\n\nYou could also use _MSC_FULL_VER, which is a bit more complete.\n\n> \t#endif\n>   }\n>\n> The thinking being - this way if I decide to use, say, LLVM + glibc,\n> then I don't need to reimplement this command with all the glibc\n> diagnostics again. Or, if someone else already wrote diagnostics for\n> LLVM with some other libc, then it even Just Works for me and my new\n> combination.\n>\n> That said, I'm reasoning about these combinations of compilers and libcs\n> and whatever else from an inexperienced viewpoint, so maybe this isn't\n> necessary?\n\nI would have hoped that the argument I made earlier about the broken GCC\nversion would have convinced you that the answer to this question is: Yes,\nthis is necessary.\n\nCiao,\nDscho\n\n>\n>  - Emily\n>\n"},{"id":"392213","messageId":"nycvar.QRO.7.76.6.2002202333340.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"xmqqpneacim1.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 07/15] bugreport: add git-remote-https version","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-02-20T22:33:52Z","receivedAt":"2020-02-20T22:34:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 19 Feb 2020, Junio C Hamano wrote:\n\n> Emily Shaffer <emilyshaffer@google.com> writes:\n>\n> >> Also, in keeping with the existing code, we would need to use\n> >> `--build-options` here (this is what `git version` calls the equivalent\n> >> mode).\n> >>\n> >> _However_.\n> >>\n> >> I like your `--build-info` a lot more than `--build-options` (because the\n> >> latter is very misleading: the commit and the date of the build are not\n> >> \"options\" at all).\n> >\n> > Sure. Thanks for saying so.\n>\n> I don't think anybody would mind introducing --build-info to \"git\n> version\" as a synonym and deprecate --build-options from it ;-)\n\nHeh. I almost suggested this. Almost.\n\nCiao,\nDscho\n"},{"id":"392223","messageId":"20200220233323.GI2447@google.com","threadId":"52442","inReplyTo":"nycvar.QRO.7.76.6.2002202306390.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v7 06/15] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-20T23:33:23Z","receivedAt":"2020-02-20T23:33:30Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Thu, Feb 20, 2020 at 11:33:05PM +0100, Johannes Schindelin wrote:\n> Hi Emily,\n> \n> On Wed, 19 Feb 2020, Emily Shaffer wrote:\n> \n> >   #ifdef __GLIBC__\n> >   #include <gnu/libc-version.h>\n> >   #endif\n> >\n> >   static inline void get_compiler_info(struct strbuf *info)\n> >   {\n> >   \t#ifdef __GLIBC__\n> > \tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n> > \t#endif\n> >\n> > \t#ifdef __GNUC__\n> > \tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n> > \t#endif\n> >\n> > \t#ifdef _MSC_VER\n> > \tstrbuf_addf(info, \"msc runtime: %s\\n\", some_msc_info());\n> \n> You could do it this way right away:\n> \n> \tstrbuf_addf(info, \"MSVC version: %d.%d\\n\",\n> \t\t    _MSC_VER / 100, _MSC_VER % 100);\n> \n> Note: this is _not_ the MSVC _runtime_ version, but really the compiler\n> version.\n> \n> You could also use _MSC_FULL_VER, which is a bit more complete.\n\nSorry, but I'm not comfortable sending code I can't check for myself\n(and already muscle-memoried into my format-patch/send-email workflow).\nIf you send a scissors I can roll it into the series with your SOB.\n\n - Emily\n"},{"id":"392267","messageId":"nycvar.QRO.7.76.6.2002211621470.46@tvgsbejvaqbjf.bet","threadId":"52442","inReplyTo":"20200220233323.GI2447@google.com","subject":"Re: [PATCH v7 06/15] bugreport: add compiler info","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-02-21T15:22:43Z","receivedAt":"2020-02-21T15:22:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Emily,\n\nOn Thu, 20 Feb 2020, Emily Shaffer wrote:\n\n> On Thu, Feb 20, 2020 at 11:33:05PM +0100, Johannes Schindelin wrote:\n> > Hi Emily,\n> >\n> > On Wed, 19 Feb 2020, Emily Shaffer wrote:\n> >\n> > >   #ifdef __GLIBC__\n> > >   #include <gnu/libc-version.h>\n> > >   #endif\n> > >\n> > >   static inline void get_compiler_info(struct strbuf *info)\n> > >   {\n> > >   \t#ifdef __GLIBC__\n> > > \tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n> > > \t#endif\n> > >\n> > > \t#ifdef __GNUC__\n> > > \tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n> > > \t#endif\n> > >\n> > > \t#ifdef _MSC_VER\n> > > \tstrbuf_addf(info, \"msc runtime: %s\\n\", some_msc_info());\n> >\n> > You could do it this way right away:\n> >\n> > \tstrbuf_addf(info, \"MSVC version: %d.%d\\n\",\n> > \t\t    _MSC_VER / 100, _MSC_VER % 100);\n> >\n> > Note: this is _not_ the MSVC _runtime_ version, but really the compiler\n> > version.\n> >\n> > You could also use _MSC_FULL_VER, which is a bit more complete.\n>\n> Sorry, but I'm not comfortable sending code I can't check for myself\n> (and already muscle-memoried into my format-patch/send-email workflow).\n> If you send a scissors I can roll it into the series with your SOB.\n\nBut you can check it yourself! I worked _really_ hard on that Azure\nPipeline backing the PR builds at https://github.com/git/git. _REALLY_\nhard. You might just as well reap the benefits so that I did not spend all\nof that time and sweat and stress in vain...\n\nCiao,\nDscho\n"},{"id":"392286","messageId":"20200222000438.GL2447@google.com","threadId":"52442","inReplyTo":"nycvar.QRO.7.76.6.2002211621470.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v7 06/15] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-02-22T00:04:38Z","receivedAt":"2020-02-22T00:04:46Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Fri, Feb 21, 2020 at 04:22:43PM +0100, Johannes Schindelin wrote:\n> Hi Emily,\n> \n> On Thu, 20 Feb 2020, Emily Shaffer wrote:\n> \n> > On Thu, Feb 20, 2020 at 11:33:05PM +0100, Johannes Schindelin wrote:\n> > > Hi Emily,\n> > >\n> > > On Wed, 19 Feb 2020, Emily Shaffer wrote:\n> > >\n> > > >   #ifdef __GLIBC__\n> > > >   #include <gnu/libc-version.h>\n> > > >   #endif\n> > > >\n> > > >   static inline void get_compiler_info(struct strbuf *info)\n> > > >   {\n> > > >   \t#ifdef __GLIBC__\n> > > > \tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n> > > > \t#endif\n> > > >\n> > > > \t#ifdef __GNUC__\n> > > > \tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n> > > > \t#endif\n> > > >\n> > > > \t#ifdef _MSC_VER\n> > > > \tstrbuf_addf(info, \"msc runtime: %s\\n\", some_msc_info());\n> > >\n> > > You could do it this way right away:\n> > >\n> > > \tstrbuf_addf(info, \"MSVC version: %d.%d\\n\",\n> > > \t\t    _MSC_VER / 100, _MSC_VER % 100);\n> > >\n> > > Note: this is _not_ the MSVC _runtime_ version, but really the compiler\n> > > version.\n> > >\n> > > You could also use _MSC_FULL_VER, which is a bit more complete.\n> >\n> > Sorry, but I'm not comfortable sending code I can't check for myself\n> > (and already muscle-memoried into my format-patch/send-email workflow).\n> > If you send a scissors I can roll it into the series with your SOB.\n> \n> But you can check it yourself! I worked _really_ hard on that Azure\n> Pipeline backing the PR builds at https://github.com/git/git. _REALLY_\n> hard. You might just as well reap the benefits so that I did not spend all\n> of that time and sweat and stress in vain...\n\nI thought a bit about this. From your Github-using point of view, \"just\ncheck my Pipeline\" sounds like \"just look at one more thing\". From my\nformat-patch using point of view, \"just check my Pipeline\" sounds like\n\"ugh, I have to add this remote again... I don't have a fork already?\nHow do I make that? Or is my fork just 6 months behind? How do I open a\nPR again? Yeesh.\"\n\nSo I did what any good developer who's supposed to be writing\nsemi-annual performance reviews would, and wrote a first pass at script\nwith this brand new fancy 'gh' thing (which is, by the way, clearly not\nintended for scripting): https://github.com/nasamuffin/quimby. Maybe\nsomeone will find it useful.\n\nI'll try and add your MSC snippet for the next rollup.\n\n - Emily\n\nP.S. You can thank Jonathan Nieder for the name, as I asked for ideas\nand he said \"Wikipedia tells me Chief Quimby gives Inspector Gadget\nsomething to read that later self-destructs.\" :P\n"},{"id":"392371","messageId":"xmqq7e0csngm.fsf@gitster-ct.c.googlers.com","threadId":"52442","inReplyTo":"20200222000438.GL2447@google.com","subject":"Re: [PATCH v7 06/15] bugreport: add compiler info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-02-24T02:55:53Z","receivedAt":"2020-02-24T02:56:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n>> > Sorry, but I'm not comfortable sending code I can't check for myself\n>> > (and already muscle-memoried into my format-patch/send-email workflow).\n>> > If you send a scissors I can roll it into the series with your SOB.\n>> \n>> But you can check it yourself! I worked _really_ hard on that Azure\n>> Pipeline backing the PR builds at https://github.com/git/git. _REALLY_\n>> hard. You might just as well reap the benefits so that I did not spend all\n>> of that time and sweat and stress in vain...\n>\n> I thought a bit about this. From your Github-using point of view, \"just\n> check my Pipeline\" sounds like \"just look at one more thing\". From my\n> format-patch using point of view, \"just check my Pipeline\" sounds like\n> \"ugh, I have to add this remote again... I don't have a fork already?\n> How do I make that? Or is my fork just 6 months behind? How do I open a\n> PR again? Yeesh.\"\n\nSorry, but this is how a typical conversation between two techies who\nare more intelligent than good for their social skills ;-)  Each side\nis not extending its hand enough to reach the other side, expecting\nthat what s/he knows should be obvious to the others.\n\nDscho may be frustrated for you not being aware of what he worked\non, but \"I worked really hard\" is much less useful thing for others,\nwho may benefit from what he worked hard on, to hear, than \"here is\none pager that tells you how to use it\".  Quite honestly, reading\nthe above exchange from the sidelines, it is not clear to me if it\nis a part of, or a completely separate from, the service offered by\nGGG from the end-users' point of view.\n\nCan some of you come up with a one-pager to cover the following (and\nrelated but not listed) areas, that can be added as an appendix to\nDocumentation/SubmittingPatches?  It does not have to cover the\ncommon stuff like style guidelines, writing good log messages, need\nfor test coverage, choice of fork point, etc.  \"Now you have a patch\nor a series of patches, but you obviously do not have direct and\npersonal access to all the platforms Git supports.  But there are\nservies to help you test them on the more common ones.\"\n\n - How to cause TravisCI to run our test suite with your\n   modification.\n\n - How to trigger the same on Azure Pipeline PR builds.\n\nThere may be others.\n\nThanks.\n"}]}