git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [Git 2.13.0] BUG: setup_git_env called without repository
@ 2017-05-12 14:19 Josh Hagins
  2017-05-12 14:48 ` Johannes Schindelin
  2017-05-12 20:34 ` [PATCH] config: complain about --local outside of a git repo Jeff King
  0 siblings, 2 replies; 25+ messages in thread
From: Josh Hagins @ 2017-05-12 14:19 UTC (permalink / raw)
  To: Git Mailing List

Hey Git people,

Since upgrading to Git 2.13.0 I'm seeing this error message whenever
`git config --local <whatever>` is called outside a Git repository.
For example, note the difference in behavior between Git 2.13 and
Apple Git:

    $ pwd
    /Users/jhagins
    $ /usr/bin/git --version
    git version 2.11.0 (Apple Git-81)
    $ /usr/bin/git config --local --get user.name
    $ /usr/local/bin/git --version
    git version 2.13.0
    $ /usr/local/bin/git config --local --get user.name
    fatal: BUG: setup_git_env called without repository

Apple Git outputs nothing, as expected. The summarized release notes
published by GitHub specifically mentioned that instances of this
error message should be reported, so here you go!

Please let me know if I can provide any more information that would be helpful.

Cheers!

-- 
Josh Hagins

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Git 2.13.0] BUG: setup_git_env called without repository
  2017-05-12 14:19 [Git 2.13.0] BUG: setup_git_env called without repository Josh Hagins
@ 2017-05-12 14:48 ` Johannes Schindelin
  2017-05-15  0:22   ` Josh Hagins
  2017-05-12 20:34 ` [PATCH] config: complain about --local outside of a git repo Jeff King
  1 sibling, 1 reply; 25+ messages in thread
From: Johannes Schindelin @ 2017-05-12 14:48 UTC (permalink / raw)
  To: Josh Hagins; +Cc: Git Mailing List

Hi Josh,

On Fri, 12 May 2017, Josh Hagins wrote:

> Since upgrading to Git 2.13.0 I'm seeing this error message whenever
> `git config --local <whatever>` is called outside a Git repository.
> For example, note the difference in behavior between Git 2.13 and
> Apple Git:
> 
>     $ pwd
>     /Users/jhagins
>     $ /usr/bin/git --version
>     git version 2.11.0 (Apple Git-81)
>     $ /usr/bin/git config --local --get user.name
>     $ /usr/local/bin/git --version
>     git version 2.13.0
>     $ /usr/local/bin/git config --local --get user.name
>     fatal: BUG: setup_git_env called without repository
> 
> Apple Git outputs nothing, as expected. The summarized release notes
> published by GitHub specifically mentioned that instances of this
> error message should be reported, so here you go!
> 
> Please let me know if I can provide any more information that would be
> helpful.

Since this is in /usr/local/bin/, there are two possibilities:

1) you built and installed it yourself (but then it would be more likely
   in your $HOME/bin), or

2) you installed it via HomeBrew.

I guess it is the latter.

In both cases, however, you have XCode installed, so you can dig further.
Yay.

The thing I would do in your case would be to clone Git:

	git clone https://github.com/git/git

then check out v2.13.0:

	git checkout v2.13.0

then edit the Makefile to remove the -O2 from the CFLAGS (the next step is
to use the GNU debugger, and in my hands the -O2 optimization made that
pretty useless), and then build with

	make

After that, you should be able to start the command in your local GNU
debugger:

	gdb -args ./git config --local --get user.name

You will then want to set a breakpoint on the die_builtin() function:

	b die_builtin

Now run it with the `r` command, and it should stop in the die_builtin
routine, in which case a backtrace would be most helpful to figure out
what is going wrong:

	bt

If the output is not enlightening on its own, it would be nice to paste it
into a reply to this mail so that the entire Git developer community can
have a look.

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] config: complain about --local outside of a git repo
  2017-05-12 14:19 [Git 2.13.0] BUG: setup_git_env called without repository Josh Hagins
  2017-05-12 14:48 ` Johannes Schindelin
@ 2017-05-12 20:34 ` Jeff King
  2017-05-12 22:31   ` Ævar Arnfjörð Bjarmason
                     ` (2 more replies)
  1 sibling, 3 replies; 25+ messages in thread
From: Jeff King @ 2017-05-12 20:34 UTC (permalink / raw)
  To: Josh Hagins; +Cc: Git Mailing List

On Fri, May 12, 2017 at 10:19:59AM -0400, Josh Hagins wrote:

> Since upgrading to Git 2.13.0 I'm seeing this error message whenever
> `git config --local <whatever>` is called outside a Git repository.
> For example, note the difference in behavior between Git 2.13 and
> Apple Git:
> 
>     $ pwd
>     /Users/jhagins
>     $ /usr/bin/git --version
>     git version 2.11.0 (Apple Git-81)
>     $ /usr/bin/git config --local --get user.name
>     $ /usr/local/bin/git --version
>     git version 2.13.0
>     $ /usr/local/bin/git config --local --get user.name
>     fatal: BUG: setup_git_env called without repository
> 
> Apple Git outputs nothing, as expected. The summarized release notes
> published by GitHub specifically mentioned that instances of this
> error message should be reported, so here you go!

Thanks for reporting. All the developers have been running with this
change for months, but I knew as soon as it was released into the wild
that somebody would find a new corner case. :)

I think dying is the right thing here; you are asking for "--local" but
there is no local repository. But we should never hit a BUG assertion.
Patch is below.

I'm not sure exactly what you wanted to accomplish with --local. If you
just want to know if user.name is set anywhere (and you may or may not
be in a git repo), then just "git config --get user.name" would work. If
you want to know if you're in a local repo and if so whether the
variable is set, you'd need to use two commands, like:

  git rev-parse --git-dir >/dev/null 2>&1 &&
  git config --local --get user.name

-- >8 --
Subject: [PATCH] config: complain about --local outside of a git repo

The "--local" option instructs git-config to read or modify
the repository-level config. This doesn't make any sense if
you're not actually in a repository.

Older versions of Git would blindly try to read or write
".git/config". For reading, this would result in a quiet
failure, since there was no config to read (and thus no
matching config value). Writing would generally fail
noisily, since ".git" was unlikely to exist. But since
b1ef400ee (setup_git_env: avoid blind fall-back to ".git",
2016-10-20), we catch this in the call to git_pathdup() and
die("BUG").

Dying is the right thing to do, but we should catch the
problem early and give a more human-friendly error message.

Note that even without --local, git-config will sometimes
default to using local repository config. These cases are
already protected by a similar check.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/config.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/config.c b/builtin/config.c
index 3a554ad50..ad7c6a19c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -496,6 +496,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_config_usage, builtin_config_options);
 	}
 
+	if (use_local_config && nongit)
+		die(_("--local only be used inside a git repository"));
+
 	if (given_config_source.file &&
 			!strcmp(given_config_source.file, "-")) {
 		given_config_source.file = NULL;
-- 
2.13.0.452.g0afc8e12b


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] config: complain about --local outside of a git repo
  2017-05-12 20:34 ` [PATCH] config: complain about --local outside of a git repo Jeff King
@ 2017-05-12 22:31   ` Ævar Arnfjörð Bjarmason
  2017-05-13  2:03     ` Jeff King
  2017-05-13  0:04   ` [PATCH] config: complain about --local outside of a git repo Jonathan Nieder
  2017-05-15  0:31   ` Josh Hagins
  2 siblings, 1 reply; 25+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2017-05-12 22:31 UTC (permalink / raw)
  To: Jeff King; +Cc: Josh Hagins, Git Mailing List

On Fri, May 12, 2017 at 10:34 PM, Jeff King <peff@peff.net> wrote:
> On Fri, May 12, 2017 at 10:19:59AM -0400, Josh Hagins wrote:
>
>> Since upgrading to Git 2.13.0 I'm seeing this error message whenever
>> `git config --local <whatever>` is called outside a Git repository.
>> For example, note the difference in behavior between Git 2.13 and
>> Apple Git:
>>
>>     $ pwd
>>     /Users/jhagins
>>     $ /usr/bin/git --version
>>     git version 2.11.0 (Apple Git-81)
>>     $ /usr/bin/git config --local --get user.name
>>     $ /usr/local/bin/git --version
>>     git version 2.13.0
>>     $ /usr/local/bin/git config --local --get user.name
>>     fatal: BUG: setup_git_env called without repository
>>
>> Apple Git outputs nothing, as expected. The summarized release notes
>> published by GitHub specifically mentioned that instances of this
>> error message should be reported, so here you go!
>
> Thanks for reporting. All the developers have been running with this
> change for months, but I knew as soon as it was released into the wild
> that somebody would find a new corner case. :)
>
> I think dying is the right thing here; you are asking for "--local" but
> there is no local repository. But we should never hit a BUG assertion.
> Patch is below.
>
> I'm not sure exactly what you wanted to accomplish with --local. If you
> just want to know if user.name is set anywhere (and you may or may not
> be in a git repo), then just "git config --get user.name" would work. If
> you want to know if you're in a local repo and if so whether the
> variable is set, you'd need to use two commands, like:
>
>   git rev-parse --git-dir >/dev/null 2>&1 &&
>   git config --local --get user.name
>
> -- >8 --
> Subject: [PATCH] config: complain about --local outside of a git repo
>
> The "--local" option instructs git-config to read or modify
> the repository-level config. This doesn't make any sense if
> you're not actually in a repository.
>
> Older versions of Git would blindly try to read or write
> ".git/config". For reading, this would result in a quiet
> failure, since there was no config to read (and thus no
> matching config value). Writing would generally fail
> noisily, since ".git" was unlikely to exist. But since
> b1ef400ee (setup_git_env: avoid blind fall-back to ".git",
> 2016-10-20), we catch this in the call to git_pathdup() and
> die("BUG").
>
> Dying is the right thing to do, but we should catch the
> problem early and give a more human-friendly error message.
>
> Note that even without --local, git-config will sometimes
> default to using local repository config. These cases are
> already protected by a similar check.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
>  builtin/config.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/builtin/config.c b/builtin/config.c
> index 3a554ad50..ad7c6a19c 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -496,6 +496,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
>                 usage_with_options(builtin_config_usage, builtin_config_options);
>         }
>
> +       if (use_local_config && nongit)
> +               die(_("--local only be used inside a git repository"));
> +
>         if (given_config_source.file &&
>                         !strcmp(given_config_source.file, "-")) {
>                 given_config_source.file = NULL;
> --
> 2.13.0.452.g0afc8e12b

It would be better to have a test for edge cases that are currently
only being discovered by users in the wild.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] config: complain about --local outside of a git repo
  2017-05-12 20:34 ` [PATCH] config: complain about --local outside of a git repo Jeff King
  2017-05-12 22:31   ` Ævar Arnfjörð Bjarmason
@ 2017-05-13  0:04   ` Jonathan Nieder
  2017-05-13  2:04     ` Jeff King
  2017-05-15  0:31   ` Josh Hagins
  2 siblings, 1 reply; 25+ messages in thread
From: Jonathan Nieder @ 2017-05-13  0:04 UTC (permalink / raw)
  To: Jeff King; +Cc: Josh Hagins, Git Mailing List

Jeff King wrote:

> Subject: [PATCH] config: complain about --local outside of a git repo
>
> The "--local" option instructs git-config to read or modify
> the repository-level config. This doesn't make any sense if
> you're not actually in a repository.
>
> Older versions of Git would blindly try to read or write
> ".git/config". For reading, this would result in a quiet
> failure, since there was no config to read (and thus no
> matching config value). Writing would generally fail
> noisily, since ".git" was unlikely to exist. But since
> b1ef400ee (setup_git_env: avoid blind fall-back to ".git",
> 2016-10-20), we catch this in the call to git_pathdup() and
> die("BUG").
>
> Dying is the right thing to do, but we should catch the
> problem early and give a more human-friendly error message.
>
> Note that even without --local, git-config will sometimes
> default to using local repository config. These cases are
> already protected by a similar check.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
>  builtin/config.c | 3 +++
>  1 file changed, 3 insertions(+)

Makes sense.

> diff --git a/builtin/config.c b/builtin/config.c
> index 3a554ad50..ad7c6a19c 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -496,6 +496,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
>  		usage_with_options(builtin_config_usage, builtin_config_options);
>  	}
> 
> +	if (use_local_config && nongit)
> +		die(_("--local only be used inside a git repository"));
> +

The output would be

	fatal: --local only be used inside a git repository

Is that missing a "should" before "only"?

With that change,
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] config: complain about --local outside of a git repo
  2017-05-12 22:31   ` Ævar Arnfjörð Bjarmason
@ 2017-05-13  2:03     ` Jeff King
  2017-05-13  3:24       ` [PATCH 0/3] BUG() and "config --local" outside of repo Jeff King
  0 siblings, 1 reply; 25+ messages in thread
From: Jeff King @ 2017-05-13  2:03 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Josh Hagins, Git Mailing List

On Sat, May 13, 2017 at 12:31:31AM +0200, Ævar Arnfjörð Bjarmason wrote:

> > +       if (use_local_config && nongit)
> > +               die(_("--local only be used inside a git repository"));
> > +
> 
> It would be better to have a test for edge cases that are currently
> only being discovered by users in the wild.

I actually started on one earlier, but what would it check? We already
die() in this case. Should we be grepping for the message? It seems more
likely to me that we would change the message and cause a false positive
than that there would be an actual regression.

What I think might be more interesting is if die("BUG") could learn to
exit with some error code that the test suite considered invalid. Like
calling abort(), which would kill us with SIGABRT and cause
test_must_fail to complain.

On many systems that would also generate a coredump. Which is handy
sometimes, but I wonder if it would be inconvenient for others. I guess
that is no different than what a raised assert() would do.

But if we were to do that, then the test could easily demonstrate that
we expect a clean die().

-Peff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] config: complain about --local outside of a git repo
  2017-05-13  0:04   ` [PATCH] config: complain about --local outside of a git repo Jonathan Nieder
@ 2017-05-13  2:04     ` Jeff King
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff King @ 2017-05-13  2:04 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Josh Hagins, Git Mailing List

On Fri, May 12, 2017 at 05:04:42PM -0700, Jonathan Nieder wrote:

> > diff --git a/builtin/config.c b/builtin/config.c
> > index 3a554ad50..ad7c6a19c 100644
> > --- a/builtin/config.c
> > +++ b/builtin/config.c
> > @@ -496,6 +496,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
> >  		usage_with_options(builtin_config_usage, builtin_config_options);
> >  	}
> > 
> > +	if (use_local_config && nongit)
> > +		die(_("--local only be used inside a git repository"));
> > +
> 
> The output would be
> 
> 	fatal: --local only be used inside a git repository
> 
> Is that missing a "should" before "only"?

Urgh, I meant "can" (I had originally written "only makes sense" but
changed it at the list minute).

I'll re-roll after thinking about the test issues raised in the other
part of the thread.

-Peff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 0/3] BUG() and "config --local" outside of repo
  2017-05-13  2:03     ` Jeff King
@ 2017-05-13  3:24       ` Jeff King
  2017-05-13  3:28         ` [PATCH 1/3] usage.c: add BUG() function Jeff King
                           ` (3 more replies)
  0 siblings, 4 replies; 25+ messages in thread
From: Jeff King @ 2017-05-13  3:24 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Josh Hagins, Git Mailing List

On Fri, May 12, 2017 at 10:03:46PM -0400, Jeff King wrote:

> On Sat, May 13, 2017 at 12:31:31AM +0200, Ævar Arnfjörð Bjarmason wrote:
> 
> > > +       if (use_local_config && nongit)
> > > +               die(_("--local only be used inside a git repository"));
> > > +
> > 
> > It would be better to have a test for edge cases that are currently
> > only being discovered by users in the wild.
> 
> I actually started on one earlier, but what would it check? We already
> die() in this case. Should we be grepping for the message? It seems more
> likely to me that we would change the message and cause a false positive
> than that there would be an actual regression.
> 
> What I think might be more interesting is if die("BUG") could learn to
> exit with some error code that the test suite considered invalid. Like
> calling abort(), which would kill us with SIGABRT and cause
> test_must_fail to complain.
> 
> On many systems that would also generate a coredump. Which is handy
> sometimes, but I wonder if it would be inconvenient for others. I guess
> that is no different than what a raised assert() would do.
> 
> But if we were to do that, then the test could easily demonstrate that
> we expect a clean die().

So here's a series which does that (and fixes the gramm-o that Jonathan
pointed out). The SIGABRT/coredump thing may seem like overkill, but
it's actually something I've found useful before (while developing this
very same setup_git_env assertion, in fact).

  [1/3]: usage.c: add BUG() function
  [2/3]: setup_git_env: convert die("BUG") to BUG()
  [3/3]: config: complain about --local outside of a git repo

 builtin/config.c       |  3 +++
 environment.c          |  2 +-
 git-compat-util.h      |  9 +++++++++
 t/t1300-repo-config.sh |  6 ++++++
 usage.c                | 32 ++++++++++++++++++++++++++++++++
 5 files changed, 51 insertions(+), 1 deletion(-)

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 1/3] usage.c: add BUG() function
  2017-05-13  3:24       ` [PATCH 0/3] BUG() and "config --local" outside of repo Jeff King
@ 2017-05-13  3:28         ` Jeff King
  2017-05-13  3:55           ` Jeff King
  2017-05-13  3:29         ` [PATCH 2/3] setup_git_env: convert die("BUG") to BUG() Jeff King
                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 25+ messages in thread
From: Jeff King @ 2017-05-13  3:28 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Josh Hagins, Git Mailing List

There's a convention in Git's code base to write assertions
as:

  if (...some_bad_thing...)
	die("BUG: the terrible thing happened");

with the idea that users should never see a "BUG:" message
(but if they, it at least gives a clue what happened).  We
use die() here because it's convenient, but there are a few
draw-backs:

  1. Without parsing the messages, it's hard for callers to
     distinguish BUG assertions from regular errors.

     For instance, it would be nice if the test suite could
     check that we don't hit any assertions, but
     test_must_fail will pass BUG deaths as OK.

  2. It would be useful to add more debugging features to
     BUG assertions, like file/line numbers or dumping core.

  3. The die() handler can be replaced, and might not
     actually exit the whole program (e.g., it may just
     pthread_exit()). This is convenient for normal errors,
     but for an assertion failure (which is supposed to
     never happen), we're probably better off taking down
     the whole process as quickly and cleanly as possible.

We could address these by checking in die() whether the
error message starts with "BUG", and behaving appropriately.
But there's little advantage at that point to sharing the
die() code, and only downsides (e.g., we can't change the
BUG() interface independently). Moreover, converting all of
the existing BUG calls reveals that the test suite does
indeed trigger a few of them.

Instead, this patch introduces a new BUG() function, which
prints an error before dying via SIGABRT. This gives us test
suite checking and core dumps.  The function is actually a
macro (when supported) so that we can show the file/line
number.

We can convert die("BUG") invocations to BUG() in further
patches, dealing with any test fallouts individually.

Signed-off-by: Jeff King <peff@peff.net>
---
I actually don't care that much about the file/line thing
personally. The messages are generally unique, which lets
you find them in the code base easily. And it does introduce
a lot of complexity due to the variadic macro fallback. So
we could just drop it and have a much simpler patch
(basically just die() without the abstracted handler, and
with abort() instead of exit()).

 git-compat-util.h |  9 +++++++++
 usage.c           | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index bd04564a6..4575b3890 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1064,6 +1064,15 @@ static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size,
 #define HAVE_VARIADIC_MACROS 1
 #endif
 
+#ifdef HAVE_VARIADIC_MACROS
+__attribute__((format (printf, 3, 4))) NORETURN
+void BUG_fl(const char *file, int line, const char *fmt, ...);
+#define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__)
+#else
+__attribute__((format (printf, 1, 2))) NORETURN
+void BUG(const char *fmt, ...);
+#endif
+
 /*
  * Preserves errno, prints a message, but gives no warning for ENOENT.
  * Returns 0 on success, which includes trying to unlink an object that does
diff --git a/usage.c b/usage.c
index ad6d2910f..7e6cb2028 100644
--- a/usage.c
+++ b/usage.c
@@ -201,3 +201,35 @@ void warning(const char *warn, ...)
 	warn_routine(warn, params);
 	va_end(params);
 }
+
+static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
+{
+	char prefix[256];
+
+	/* truncation via snprintf is OK here */
+	if (file)
+		snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line);
+	else
+		snprintf(prefix, sizeof(prefix), "BUG: ");
+
+	vreportf(prefix, fmt, params);
+	abort();
+}
+
+#ifdef HAVE_VARIADIC_MACROS
+void BUG_fl(const char *file, int line, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	BUG_vfl(file, line, fmt, ap);
+	va_end(ap);
+}
+#else
+void BUG(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	BUG_vfl(NULL, 0, fmt, ap);
+	va_end(ap);
+}
+#endif
-- 
2.13.0.452.g0afc8e12b


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 2/3] setup_git_env: convert die("BUG") to BUG()
  2017-05-13  3:24       ` [PATCH 0/3] BUG() and "config --local" outside of repo Jeff King
  2017-05-13  3:28         ` [PATCH 1/3] usage.c: add BUG() function Jeff King
@ 2017-05-13  3:29         ` Jeff King
  2017-05-13  3:29         ` [PATCH 3/3] config: complain about --local outside of a git repo Jeff King
  2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
  3 siblings, 0 replies; 25+ messages in thread
From: Jeff King @ 2017-05-13  3:29 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Josh Hagins, Git Mailing List

Converting to BUG() makes it easier to detect and debug
cases where we hit this assertion. Coupled with a new test
in t1300, this shows that the test suite can detect such
corner cases.

Signed-off-by: Jeff King <peff@peff.net>
---
 environment.c          | 2 +-
 t/t1300-repo-config.sh | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/environment.c b/environment.c
index ff6e4f06e..1f0bda5af 100644
--- a/environment.c
+++ b/environment.c
@@ -169,7 +169,7 @@ static void setup_git_env(void)
 	git_dir = getenv(GIT_DIR_ENVIRONMENT);
 	if (!git_dir) {
 		if (!startup_info->have_repository)
-			die("BUG: setup_git_env called without repository");
+			BUG("setup_git_env called without repository");
 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 	}
 	gitfile = read_gitfile(git_dir);
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index afcca0d52..867704a64 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -1539,4 +1539,10 @@ test_expect_success !MINGW '--show-origin blob ref' '
 	test_cmp expect output
 '
 
+test_expect_failure '--local requires a repo' '
+	# we expect 128 to ensure that we do not simply
+	# fail to find anything and return code "1"
+	test_expect_code 128 nongit git config --local foo.bar
+'
+
 test_done
-- 
2.13.0.452.g0afc8e12b


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 3/3] config: complain about --local outside of a git repo
  2017-05-13  3:24       ` [PATCH 0/3] BUG() and "config --local" outside of repo Jeff King
  2017-05-13  3:28         ` [PATCH 1/3] usage.c: add BUG() function Jeff King
  2017-05-13  3:29         ` [PATCH 2/3] setup_git_env: convert die("BUG") to BUG() Jeff King
@ 2017-05-13  3:29         ` Jeff King
  2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
  3 siblings, 0 replies; 25+ messages in thread
From: Jeff King @ 2017-05-13  3:29 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Josh Hagins, Git Mailing List

The "--local" option instructs git-config to read or modify
the repository-level config. This doesn't make any sense if
you're not actually in a repository.

Older versions of Git would blindly try to read or write
".git/config". For reading, this would result in a quiet
failure, since there was no config to read (and thus no
matching config value). Writing would generally fail
noisily, since ".git" was unlikely to exist. But since
b1ef400ee (setup_git_env: avoid blind fall-back to ".git",
2016-10-20), we catch this in the call to git_pathdup() and
die with an assertion.

Dying is the right thing to do, but we should catch the
problem early and give a more human-friendly error message.

Note that even without --local, git-config will sometimes
default to using local repository config (e.g., when
writing). These cases are already protected by similar
checks, and covered by a test in t1308.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/config.c       | 3 +++
 t/t1300-repo-config.sh | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/builtin/config.c b/builtin/config.c
index 3a554ad50..7f6c25d4d 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -496,6 +496,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_config_usage, builtin_config_options);
 	}
 
+	if (use_local_config && nongit)
+		die(_("--local can only be used inside a git repository"));
+
 	if (given_config_source.file &&
 			!strcmp(given_config_source.file, "-")) {
 		given_config_source.file = NULL;
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 867704a64..13b7851f7 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -1539,7 +1539,7 @@ test_expect_success !MINGW '--show-origin blob ref' '
 	test_cmp expect output
 '
 
-test_expect_failure '--local requires a repo' '
+test_expect_success '--local requires a repo' '
 	# we expect 128 to ensure that we do not simply
 	# fail to find anything and return code "1"
 	test_expect_code 128 nongit git config --local foo.bar
-- 
2.13.0.452.g0afc8e12b

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/3] usage.c: add BUG() function
  2017-05-13  3:28         ` [PATCH 1/3] usage.c: add BUG() function Jeff King
@ 2017-05-13  3:55           ` Jeff King
  2017-05-15  2:28             ` Junio C Hamano
  0 siblings, 1 reply; 25+ messages in thread
From: Jeff King @ 2017-05-13  3:55 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Josh Hagins, Git Mailing List

On Fri, May 12, 2017 at 11:28:50PM -0400, Jeff King wrote:

> +static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
> +{
> +	char prefix[256];
> +
> +	/* truncation via snprintf is OK here */
> +	if (file)
> +		snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line);
> +	else
> +		snprintf(prefix, sizeof(prefix), "BUG: ");
> +
> +	vreportf(prefix, fmt, params);
> +	abort();
> +}

I used vreportf() here to match die(). But the two things that function
does are:

  1. Respect error_handle. But after bw/forking-and-threading is merged,
     nobody will ever set error_handle (and I just sent a patch to drop
     it entirely).

  2. Quotes non-printable characters. I don't know how useful this is.
     Most of the assertion messages are pretty vanilla (because anything
     that relies on user input probably should be a regular die, not an
     assertion failure). But a few of them do actually print arbitrary
     strings in a reasonable way (e.g., a BUG() which is handling user
     string which was supposed to be vetted by an earlier function is
     still a reasonable assertion, but it's useful to show the string).

So an alternative would be just:

  fprintf(stderr, "BUG: ");
  if (file)
	fprintf(stderr, "%s:%d ", file, line);
  vfprintf(stderr, fmt, params);
  fputc('\n', stderr);

which is perhaps a bit simpler (not much in lines of code, but there's
no extra buffer to reason about). But given the discussion in (2) above,
it's probably worth continuing to use vreportf.

-Peff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Git 2.13.0] BUG: setup_git_env called without repository
  2017-05-12 14:48 ` Johannes Schindelin
@ 2017-05-15  0:22   ` Josh Hagins
  0 siblings, 0 replies; 25+ messages in thread
From: Josh Hagins @ 2017-05-15  0:22 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Git Mailing List

Hi Johannes,

Here's the full text of the gdb session, including backtrace. Hope it helps!

$ pwd
/Users/jhagins/dev/github
$ gdb -args ./git/git config --local --get user.name
GNU gdb (GDB) 7.12.1
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin16.4.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./git/git...done.
(gdb) b die_builtin
Breakpoint 1 at 0x100210757: file usage.c, line 33.
(gdb) r
Starting program: /Volumes/git/github/git/git config --local --get user.name
[New Thread 0x1403 of process 64101]
warning: unhandled dyld version (15)

Thread 2 hit Breakpoint 1, die_builtin (err=0x100270d95 "BUG:
setup_git_env called without repository", params=0x7fff5fbfdbe0) at
usage.c:33
33 vreportf("fatal: ", err, params);
(gdb) bt
#0  die_builtin (err=0x100270d95 "BUG: setup_git_env called without
repository", params=0x7fff5fbfdbe0) at usage.c:33
#1  0x000000010020fc80 in die (err=0x100270d95 "BUG: setup_git_env
called without repository") at usage.c:120
#2  0x000000010012cb2b in setup_git_env () at environment.c:172
#3  0x000000010012cab7 in get_git_dir () at environment.c:214
#4  0x0000000100214e9c in get_worktree_git_dir (wt=0x0) at worktree.c:215
#5  0x000000010017968c in do_git_path (wt=0x0, buf=0x7fff5fbfde50,
fmt=0x10024c24d "config", args=0x7fff5fbfde70) at path.c:395
#6  0x0000000100179c78 in git_pathdup (fmt=0x10024c24d "config") at path.c:437
#7  0x0000000100030449 in cmd_config (argc=1, argv=0x7fff5fbfe180,
prefix=0x0) at builtin/config.c:527
#8  0x0000000100001ac5 in run_builtin (p=0x10028c3a8, argc=4,
argv=0x7fff5fbfe180) at git.c:371
#9  0x0000000100000cc6 in handle_builtin (argc=4, argv=0x7fff5fbfe180)
at git.c:572
#10 0x0000000100001883 in run_argv (argcp=0x7fff5fbfe12c,
argv=0x7fff5fbfe120) at git.c:624
#11 0x0000000100000a4f in cmd_main (argc=4, argv=0x7fff5fbfe180) at git.c:701
#12 0x00000001000c3772 in main (argc=5, argv=0x7fff5fbfe178) at common-main.c:43

Cheers,
Josh

On Fri, May 12, 2017 at 10:48 AM, Johannes Schindelin
<Johannes.Schindelin@gmx.de> wrote:
> Hi Josh,
>
> On Fri, 12 May 2017, Josh Hagins wrote:
>
>> Since upgrading to Git 2.13.0 I'm seeing this error message whenever
>> `git config --local <whatever>` is called outside a Git repository.
>> For example, note the difference in behavior between Git 2.13 and
>> Apple Git:
>>
>>     $ pwd
>>     /Users/jhagins
>>     $ /usr/bin/git --version
>>     git version 2.11.0 (Apple Git-81)
>>     $ /usr/bin/git config --local --get user.name
>>     $ /usr/local/bin/git --version
>>     git version 2.13.0
>>     $ /usr/local/bin/git config --local --get user.name
>>     fatal: BUG: setup_git_env called without repository
>>
>> Apple Git outputs nothing, as expected. The summarized release notes
>> published by GitHub specifically mentioned that instances of this
>> error message should be reported, so here you go!
>>
>> Please let me know if I can provide any more information that would be
>> helpful.
>
> Since this is in /usr/local/bin/, there are two possibilities:
>
> 1) you built and installed it yourself (but then it would be more likely
>    in your $HOME/bin), or
>
> 2) you installed it via HomeBrew.
>
> I guess it is the latter.
>
> In both cases, however, you have XCode installed, so you can dig further.
> Yay.
>
> The thing I would do in your case would be to clone Git:
>
>         git clone https://github.com/git/git
>
> then check out v2.13.0:
>
>         git checkout v2.13.0
>
> then edit the Makefile to remove the -O2 from the CFLAGS (the next step is
> to use the GNU debugger, and in my hands the -O2 optimization made that
> pretty useless), and then build with
>
>         make
>
> After that, you should be able to start the command in your local GNU
> debugger:
>
>         gdb -args ./git config --local --get user.name
>
> You will then want to set a breakpoint on the die_builtin() function:
>
>         b die_builtin
>
> Now run it with the `r` command, and it should stop in the die_builtin
> routine, in which case a backtrace would be most helpful to figure out
> what is going wrong:
>
>         bt
>
> If the output is not enlightening on its own, it would be nice to paste it
> into a reply to this mail so that the entire Git developer community can
> have a look.
>
> Ciao,
> Johannes



-- 
Josh Hagins

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] config: complain about --local outside of a git repo
  2017-05-12 20:34 ` [PATCH] config: complain about --local outside of a git repo Jeff King
  2017-05-12 22:31   ` Ævar Arnfjörð Bjarmason
  2017-05-13  0:04   ` [PATCH] config: complain about --local outside of a git repo Jonathan Nieder
@ 2017-05-15  0:31   ` Josh Hagins
  2017-05-15  3:18     ` Jeff King
  2 siblings, 1 reply; 25+ messages in thread
From: Josh Hagins @ 2017-05-15  0:31 UTC (permalink / raw)
  To: Jeff King; +Cc: Git Mailing List

Hi Jeff,

For context, the "user.name" bit was purely notional; I just wanted to
give a sample reproduction. Where I've actually been running into this
in real life is with oh-my-git, a GitHub-themed Powerline bash prompt:
https://github.com/arialdomartini/oh-my-git/blob/42c11f08540949b75bd513e6880a4ce6824a2bcc/base.sh#L52.

Since this command is invoked every time the prompt is build, I see
the error message after every single command I run outside of a Git
repository. While this is more indicative of a code smell in
oh-my-git, I figured that, as you said, BUG assertions should never
get hit in the wild. Thanks for the patch!

Cheers,
Josh

On Fri, May 12, 2017 at 4:34 PM, Jeff King <peff@peff.net> wrote:
> On Fri, May 12, 2017 at 10:19:59AM -0400, Josh Hagins wrote:
>
>> Since upgrading to Git 2.13.0 I'm seeing this error message whenever
>> `git config --local <whatever>` is called outside a Git repository.
>> For example, note the difference in behavior between Git 2.13 and
>> Apple Git:
>>
>>     $ pwd
>>     /Users/jhagins
>>     $ /usr/bin/git --version
>>     git version 2.11.0 (Apple Git-81)
>>     $ /usr/bin/git config --local --get user.name
>>     $ /usr/local/bin/git --version
>>     git version 2.13.0
>>     $ /usr/local/bin/git config --local --get user.name
>>     fatal: BUG: setup_git_env called without repository
>>
>> Apple Git outputs nothing, as expected. The summarized release notes
>> published by GitHub specifically mentioned that instances of this
>> error message should be reported, so here you go!
>
> Thanks for reporting. All the developers have been running with this
> change for months, but I knew as soon as it was released into the wild
> that somebody would find a new corner case. :)
>
> I think dying is the right thing here; you are asking for "--local" but
> there is no local repository. But we should never hit a BUG assertion.
> Patch is below.
>
> I'm not sure exactly what you wanted to accomplish with --local. If you
> just want to know if user.name is set anywhere (and you may or may not
> be in a git repo), then just "git config --get user.name" would work. If
> you want to know if you're in a local repo and if so whether the
> variable is set, you'd need to use two commands, like:
>
>   git rev-parse --git-dir >/dev/null 2>&1 &&
>   git config --local --get user.name
>
> -- >8 --
> Subject: [PATCH] config: complain about --local outside of a git repo
>
> The "--local" option instructs git-config to read or modify
> the repository-level config. This doesn't make any sense if
> you're not actually in a repository.
>
> Older versions of Git would blindly try to read or write
> ".git/config". For reading, this would result in a quiet
> failure, since there was no config to read (and thus no
> matching config value). Writing would generally fail
> noisily, since ".git" was unlikely to exist. But since
> b1ef400ee (setup_git_env: avoid blind fall-back to ".git",
> 2016-10-20), we catch this in the call to git_pathdup() and
> die("BUG").
>
> Dying is the right thing to do, but we should catch the
> problem early and give a more human-friendly error message.
>
> Note that even without --local, git-config will sometimes
> default to using local repository config. These cases are
> already protected by a similar check.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
>  builtin/config.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/builtin/config.c b/builtin/config.c
> index 3a554ad50..ad7c6a19c 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -496,6 +496,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
>                 usage_with_options(builtin_config_usage, builtin_config_options);
>         }
>
> +       if (use_local_config && nongit)
> +               die(_("--local only be used inside a git repository"));
> +
>         if (given_config_source.file &&
>                         !strcmp(given_config_source.file, "-")) {
>                 given_config_source.file = NULL;
> --
> 2.13.0.452.g0afc8e12b
>



-- 
Josh Hagins

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/3] usage.c: add BUG() function
  2017-05-13  3:55           ` Jeff King
@ 2017-05-15  2:28             ` Junio C Hamano
  0 siblings, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2017-05-15  2:28 UTC (permalink / raw)
  To: Jeff King
  Cc: Ævar Arnfjörð Bjarmason, Josh Hagins,
	Git Mailing List

Jeff King <peff@peff.net> writes:

> On Fri, May 12, 2017 at 11:28:50PM -0400, Jeff King wrote:
>
>> +static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
>> +{
>> +	char prefix[256];
>> +
>> +	/* truncation via snprintf is OK here */
>> +	if (file)
>> +		snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line);
>> +	else
>> +		snprintf(prefix, sizeof(prefix), "BUG: ");
>> +
>> +	vreportf(prefix, fmt, params);
>> +	abort();
>> +}
>
> I used vreportf() here to match die(). But the two things that function
> does are:
>
>   1. Respect error_handle. But after bw/forking-and-threading is merged,
>      nobody will ever set error_handle (and I just sent a patch to drop
>      it entirely).
>
>   2. Quotes non-printable characters. I don't know how useful this is.
>      Most of the assertion messages are pretty vanilla (because anything
>      that relies on user input probably should be a regular die, not an
>      assertion failure). But a few of them do actually print arbitrary
>      strings in a reasonable way (e.g., a BUG() which is handling user
>      string which was supposed to be vetted by an earlier function is
>      still a reasonable assertion, but it's useful to show the string).
>
> So an alternative would be just:
>
>   fprintf(stderr, "BUG: ");
>   if (file)
> 	fprintf(stderr, "%s:%d ", file, line);
>   vfprintf(stderr, fmt, params);
>   fputc('\n', stderr);
>
> which is perhaps a bit simpler (not much in lines of code, but there's
> no extra buffer to reason about). But given the discussion in (2) above,
> it's probably worth continuing to use vreportf.

Yeah, that does sound sensible.  Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] config: complain about --local outside of a git repo
  2017-05-15  0:31   ` Josh Hagins
@ 2017-05-15  3:18     ` Jeff King
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff King @ 2017-05-15  3:18 UTC (permalink / raw)
  To: Josh Hagins; +Cc: Git Mailing List

On Sun, May 14, 2017 at 08:31:54PM -0400, Josh Hagins wrote:

> For context, the "user.name" bit was purely notional; I just wanted to
> give a sample reproduction. Where I've actually been running into this
> in real life is with oh-my-git, a GitHub-themed Powerline bash prompt:
> https://github.com/arialdomartini/oh-my-git/blob/42c11f08540949b75bd513e6880a4ce6824a2bcc/base.sh#L52.
> 
> Since this command is invoked every time the prompt is build, I see
> the error message after every single command I run outside of a Git
> repository. While this is more indicative of a code smell in
> oh-my-git, I figured that, as you said, BUG assertions should never
> get hit in the wild. Thanks for the patch!

Ah, thanks for the context. That makes a lot more sense. I do think
oh-my-git should just drop the "--local", which will cause git-config to
follow the usual precedence rules (and it will skip repo-level config
automatically when we are not in a repo).

Since the oh-my-git code only looks for "false", nobody would ever need
to default the value to true in their ~/.gitconfig. But respecting the
usual config rules would mean you could set it to "false" in
~/.gitconfig to turn it off everywhere, but then opt back into it for
specific repos by setting it to "true" there. Probably not a use case
anybody cares that much about, but it's how "git config" was meant to be
used. :)

Anyway, thanks again for reporting the BUG assertion. I'm glad to be
weeding out more cases.

-Peff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG()
  2017-05-13  3:24       ` [PATCH 0/3] BUG() and "config --local" outside of repo Jeff King
                           ` (2 preceding siblings ...)
  2017-05-13  3:29         ` [PATCH 3/3] config: complain about --local outside of a git repo Jeff King
@ 2018-05-02  9:38         ` Johannes Schindelin
  2018-05-02  9:38           ` [PATCH v2 1/4] test-tool: help verifying BUG() code paths Johannes Schindelin
                             ` (4 more replies)
  3 siblings, 5 replies; 25+ messages in thread
From: Johannes Schindelin @ 2018-05-02  9:38 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Junio C Hamano, Jeff King, Johannes Sixt,
	Nguyễn Thái Ngọc Duy, Eric Sunshine

The BUG() macro was introduced in this patch series:
https://public-inbox.org/git/20170513032414.mfrwabt4hovujde2@sigill.intra.peff.net

The second patch in that series converted one caller from die("BUG: ")
to use the BUG() macro.

It seems that there was no concrete plan to address the same issue in
the rest of the code base.

This patch series tries to do that.

Note: I would be very surprised if the monster commit 3/4 ("Replace all
die("BUG: ...") calls by BUG() ones") would apply cleanly on `pu` (I
develop this on top of `master`).

For that reason, the commit message contains the precise Unix shell
invocation (GNU sed semantics, not BSD sed ones, because I know that the
Git maintainer as well as the author of the patch introducing BUG() both
use Linux and not macOS or any other platform that would offer a BSD
sed). It should be straight-forward to handle merge
conflicts/non-applying patches by simply re-running that command.

Changes since v2:

- Avoided the entire discussion about the previous 2/6 (now dropped)
  that prepared t1406 to handle SIGABRT by side-stepping the issue: the
  ref-store test helper will no longer call abort() in BUG() calls but
  exit with exit code 99 instead.

- As a consequence, I could fold 3/6 into 4/6 (i.e. *not* special-case
  the refs/*.c code but do one wholesale die("BUG: ...") -> BUG()
  conversion).

- Further consequence: 1/6, which added handling for ok=sigabrt to
  test_must_fail, was dropped.

- I also used the opportunity to explain in the commit message of the last
  commit why the localization was dropped from one die(_("BUG: ...")) call.


Johannes Schindelin (4):
  test-tool: help verifying BUG() code paths
  run-command: use BUG() to report bugs, not die()
  Replace all die("BUG: ...") calls by BUG() ones
  Convert remaining die*(BUG) messages

 apply.c                          |  4 ++--
 archive-tar.c                    |  2 +-
 attr.c                           | 10 +++++-----
 blame.c                          |  2 +-
 builtin/am.c                     | 20 +++++++++----------
 builtin/branch.c                 |  2 +-
 builtin/cat-file.c               |  4 ++--
 builtin/clone.c                  |  2 +-
 builtin/commit.c                 |  2 +-
 builtin/config.c                 |  2 +-
 builtin/fast-export.c            |  2 +-
 builtin/fsck.c                   |  2 +-
 builtin/index-pack.c             |  4 ++--
 builtin/init-db.c                |  2 +-
 builtin/ls-files.c               |  2 +-
 builtin/notes.c                  |  8 ++++----
 builtin/pack-objects.c           |  4 ++--
 builtin/pull.c                   |  2 +-
 builtin/receive-pack.c           |  2 +-
 builtin/replace.c                |  2 +-
 builtin/update-index.c           |  2 +-
 bulk-checkin.c                   |  2 +-
 color.c                          |  4 ++--
 column.c                         |  2 +-
 config.c                         | 12 +++++------
 date.c                           |  2 +-
 diff.c                           | 12 +++++------
 dir-iterator.c                   |  2 +-
 git-compat-util.h                |  2 +-
 grep.c                           | 16 +++++++--------
 http.c                           |  8 ++++----
 imap-send.c                      |  2 +-
 lockfile.c                       |  2 +-
 mailinfo.c                       |  2 +-
 merge-recursive.c                | 12 +++++------
 notes-merge.c                    |  4 ++--
 pack-bitmap-write.c              |  2 +-
 pack-bitmap.c                    |  6 +++---
 pack-objects.c                   |  2 +-
 packfile.c                       |  6 +++---
 pathspec.c                       | 12 +++++------
 pkt-line.c                       |  2 +-
 prio-queue.c                     |  2 +-
 ref-filter.c                     |  4 ++--
 refs.c                           | 34 ++++++++++++++++----------------
 refs/files-backend.c             | 20 +++++++++----------
 refs/iterator.c                  |  6 +++---
 refs/packed-backend.c            | 16 +++++++--------
 refs/ref-cache.c                 |  2 +-
 remote.c                         |  2 +-
 revision.c                       |  4 ++--
 run-command.c                    | 33 ++++++++++++++-----------------
 setup.c                          |  4 ++--
 sha1-lookup.c                    |  2 +-
 sha1-name.c                      |  4 ++--
 shallow.c                        |  6 +++---
 sigchain.c                       |  2 +-
 strbuf.c                         |  4 ++--
 submodule.c                      |  8 ++++----
 t/helper/test-example-decorate.c | 16 +++++++--------
 t/helper/test-tool.c             |  2 ++
 tmp-objdir.c                     |  2 +-
 trailer.c                        |  6 +++---
 transport.c                      |  4 ++--
 unpack-trees.c                   |  2 +-
 usage.c                          |  5 +++++
 vcs-svn/fast_export.c            |  6 ++++--
 worktree.c                       |  2 +-
 wrapper.c                        |  4 ++--
 wt-status.c                      | 20 +++++++++----------
 zlib.c                           |  4 ++--
 71 files changed, 214 insertions(+), 208 deletions(-)


base-commit: 1f1cddd558b54bb0ce19c8ace353fd07b758510d
Published-As: https://github.com/dscho/git/releases/tag/use-bug-macro-v2
Fetch-It-Via: git fetch https://github.com/dscho/git use-bug-macro-v2

Branch-diff vs v1:
 1: 97894dd28d7 < -:  ------- test_must_fail: support ok=sigabrt
 2: 9bbfd73a8e0 < -:  ------- t1406: prepare for the refs code to fail with BUG()
 3: b44ce003ae6 < -:  ------- refs/*: report bugs using the BUG() macro
 -:  ------- > 1: 6e2bfd3a6eb test-tool: help verifying BUG() code paths
 4: 89539a1af3d = 2: 91ddc7ed5ce run-command: use BUG() to report bugs, not die()
 5: 42584f2f7c9 ! 3: 2133197fdc9 Replace all die("BUG: ...") calls by BUG() ones
     @@ -1199,6 +1199,214 @@
       	extra_refname = find_descendant_ref(dirname.buf, extras, skip);
       	if (extra_refname)
      
     +diff --git a/refs/files-backend.c b/refs/files-backend.c
     +--- a/refs/files-backend.c
     ++++ b/refs/files-backend.c
     +@@
     + 	if (refs->store_flags & REF_STORE_MAIN)
     + 		return;
     + 
     +-	die("BUG: operation %s only allowed for main ref store", caller);
     ++	BUG("operation %s only allowed for main ref store", caller);
     + }
     + 
     + /*
     +@@
     + 	struct files_ref_store *refs;
     + 
     + 	if (ref_store->be != &refs_be_files)
     +-		die("BUG: ref_store is type \"%s\" not \"files\" in %s",
     ++		BUG("ref_store is type \"%s\" not \"files\" in %s",
     + 		    ref_store->be->name, caller);
     + 
     + 	refs = (struct files_ref_store *)ref_store;
     + 
     + 	if ((refs->store_flags & required_flags) != required_flags)
     +-		die("BUG: operation %s requires abilities 0x%x, but only have 0x%x",
     ++		BUG("operation %s requires abilities 0x%x, but only have 0x%x",
     + 		    caller, required_flags, refs->store_flags);
     + 
     + 	return refs;
     +@@
     + 		strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
     + 		break;
     + 	default:
     +-		die("BUG: unknown ref type %d of ref %s",
     ++		BUG("unknown ref type %d of ref %s",
     + 		    ref_type(refname), refname);
     + 	}
     + }
     +@@
     + 		strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
     + 		break;
     + 	default:
     +-		die("BUG: unknown ref type %d of ref %s",
     ++		BUG("unknown ref type %d of ref %s",
     + 		    ref_type(refname), refname);
     + 	}
     + }
     +@@
     + 
     + 	}
     + 	if (!ret && sb.len)
     +-		die("BUG: reverse reflog parser had leftover data");
     ++		BUG("reverse reflog parser had leftover data");
     + 
     + 	fclose(logfp);
     + 	strbuf_release(&sb);
     +@@
     + static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,
     + 				   struct object_id *peeled)
     + {
     +-	die("BUG: ref_iterator_peel() called for reflog_iterator");
     ++	BUG("ref_iterator_peel() called for reflog_iterator");
     + }
     + 
     + static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)
     +@@
     + 	assert(err);
     + 
     + 	if (transaction->state != REF_TRANSACTION_OPEN)
     +-		die("BUG: commit called for transaction that is not open");
     ++		BUG("commit called for transaction that is not open");
     + 
     + 	/* Fail if a refname appears more than once in the transaction: */
     + 	for (i = 0; i < transaction->nr; i++)
     +@@
     + 	 */
     + 	if (refs_for_each_rawref(&refs->base, ref_present,
     + 				 &affected_refnames))
     +-		die("BUG: initial ref transaction called with existing refs");
     ++		BUG("initial ref transaction called with existing refs");
     + 
     + 	packed_transaction = ref_store_transaction_begin(refs->packed_ref_store, err);
     + 	if (!packed_transaction) {
     +@@
     + 
     + 		if ((update->flags & REF_HAVE_OLD) &&
     + 		    !is_null_oid(&update->old_oid))
     +-			die("BUG: initial ref transaction with old_sha1 set");
     ++			BUG("initial ref transaction with old_sha1 set");
     + 		if (refs_verify_refname_available(&refs->base, update->refname,
     + 						  &affected_refnames, NULL,
     + 						  err)) {
     +
     +diff --git a/refs/iterator.c b/refs/iterator.c
     +--- a/refs/iterator.c
     ++++ b/refs/iterator.c
     +@@
     + static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator,
     + 				   struct object_id *peeled)
     + {
     +-	die("BUG: peel called for empty iterator");
     ++	BUG("peel called for empty iterator");
     + }
     + 
     + static int empty_ref_iterator_abort(struct ref_iterator *ref_iterator)
     +@@
     + 		(struct merge_ref_iterator *)ref_iterator;
     + 
     + 	if (!iter->current) {
     +-		die("BUG: peel called before advance for merge iterator");
     ++		BUG("peel called before advance for merge iterator");
     + 	}
     + 	return ref_iterator_peel(*iter->current, peeled);
     + }
     +@@
     + 			 * trimming, report it as a bug:
     + 			 */
     + 			if (strlen(iter->iter0->refname) <= iter->trim)
     +-				die("BUG: attempt to trim too many characters");
     ++				BUG("attempt to trim too many characters");
     + 			iter->base.refname = iter->iter0->refname + iter->trim;
     + 		} else {
     + 			iter->base.refname = iter->iter0->refname;
     +
     +diff --git a/refs/packed-backend.c b/refs/packed-backend.c
     +--- a/refs/packed-backend.c
     ++++ b/refs/packed-backend.c
     +@@
     + 	struct packed_ref_store *refs;
     + 
     + 	if (ref_store->be != &refs_be_packed)
     +-		die("BUG: ref_store is type \"%s\" not \"packed\" in %s",
     ++		BUG("ref_store is type \"%s\" not \"packed\" in %s",
     + 		    ref_store->be->name, caller);
     + 
     + 	refs = (struct packed_ref_store *)ref_store;
     + 
     + 	if ((refs->store_flags & required_flags) != required_flags)
     +-		die("BUG: unallowed operation (%s), requires %x, has %x\n",
     ++		BUG("unallowed operation (%s), requires %x, has %x\n",
     + 		    caller, required_flags, refs->store_flags);
     + 
     + 	return refs;
     +@@
     + 			"packed_refs_unlock");
     + 
     + 	if (!is_lock_file_locked(&refs->lock))
     +-		die("BUG: packed_refs_unlock() called when not locked");
     ++		BUG("packed_refs_unlock() called when not locked");
     + 	rollback_lock_file(&refs->lock);
     + }
     + 
     +@@
     + 	char *packed_refs_path;
     + 
     + 	if (!is_lock_file_locked(&refs->lock))
     +-		die("BUG: write_with_updates() called while unlocked");
     ++		BUG("write_with_updates() called while unlocked");
     + 
     + 	/*
     + 	 * If packed-refs is a symlink, we want to overwrite the
     +@@
     + 			       const char *refname, const char *target,
     + 			       const char *logmsg)
     + {
     +-	die("BUG: packed reference store does not support symrefs");
     ++	BUG("packed reference store does not support symrefs");
     + }
     + 
     + static int packed_rename_ref(struct ref_store *ref_store,
     + 			    const char *oldrefname, const char *newrefname,
     + 			    const char *logmsg)
     + {
     +-	die("BUG: packed reference store does not support renaming references");
     ++	BUG("packed reference store does not support renaming references");
     + }
     + 
     + static int packed_copy_ref(struct ref_store *ref_store,
     + 			   const char *oldrefname, const char *newrefname,
     + 			   const char *logmsg)
     + {
     +-	die("BUG: packed reference store does not support copying references");
     ++	BUG("packed reference store does not support copying references");
     + }
     + 
     + static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store)
     +@@
     + 			       const char *refname, int force_create,
     + 			       struct strbuf *err)
     + {
     +-	die("BUG: packed reference store does not support reflogs");
     ++	BUG("packed reference store does not support reflogs");
     + }
     + 
     + static int packed_delete_reflog(struct ref_store *ref_store,
     +
     +diff --git a/refs/ref-cache.c b/refs/ref-cache.c
     +--- a/refs/ref-cache.c
     ++++ b/refs/ref-cache.c
     +@@
     + 	dir = &entry->u.subdir;
     + 	if (entry->flag & REF_INCOMPLETE) {
     + 		if (!dir->cache->fill_ref_dir)
     +-			die("BUG: incomplete ref_store without fill_ref_dir function");
     ++			BUG("incomplete ref_store without fill_ref_dir function");
     + 
     + 		dir->cache->fill_ref_dir(dir->cache->ref_store, dir, entry->name);
     + 		entry->flag &= ~REF_INCOMPLETE;
     +
      diff --git a/remote.c b/remote.c
      --- a/remote.c
      +++ b/remote.c
 6: 0e85c7a16e3 ! 4: 57b3a3e9fe3 Convert remaining die*(BUG) messages
     @@ -4,6 +4,12 @@
          
          These were not caught by the previous commit, as they did not match the
          regular expression.
     +    
     +    While at it, remove the localization from one instance: we never want
     +    BUG() messages to be translated, as they target Git developers, not the
     +    end user (hence it would be quite unhelpful to not only burden the
     +    translators, but then even end up with a bug report in a language that
     +    no core Git contributor understands).
          
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
-- 
2.17.0.windows.1.36.gdf4ca5fb72a


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 1/4] test-tool: help verifying BUG() code paths
  2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
@ 2018-05-02  9:38           ` Johannes Schindelin
  2018-05-02 15:18             ` Duy Nguyen
  2018-05-02  9:38           ` [PATCH v2 2/4] run-command: use BUG() to report bugs, not die() Johannes Schindelin
                             ` (3 subsequent siblings)
  4 siblings, 1 reply; 25+ messages in thread
From: Johannes Schindelin @ 2018-05-02  9:38 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Junio C Hamano, Jeff King, Johannes Sixt,
	Nguyễn Thái Ngọc Duy, Eric Sunshine

When we call BUG(), we signal via SIGABRT that something bad happened,
dumping cores if so configured. In some setups these coredumps are
redirected to some central place such as /proc/sys/kernel/core_pattern,
which is a good thing.

However, when we try to verify in our test suite that bugs are caught in
certain code paths, we do *not* want to clutter such a central place
with unnecessary coredumps.

So let's special-case the test helpers (which we use to verify such code
paths) so that the BUG() calls will *not* call abort() but exit with a
special-purpose exit code instead.

Helped-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/helper/test-tool.c | 2 ++
 usage.c              | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 87066ced62a..5176f9f20ae 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -47,7 +47,9 @@ static struct test_cmd cmds[] = {
 int cmd_main(int argc, const char **argv)
 {
 	int i;
+	extern int BUG_exit_code;
 
+	BUG_exit_code = 99;
 	if (argc < 2)
 		die("I need a test name!");
 
diff --git a/usage.c b/usage.c
index cdd534c9dfc..9c84dccfa97 100644
--- a/usage.c
+++ b/usage.c
@@ -210,6 +210,9 @@ void warning(const char *warn, ...)
 	va_end(params);
 }
 
+/* Only set this, ever, from t/helper/, when verifying that bugs are caught. */
+int BUG_exit_code;
+
 static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
 {
 	char prefix[256];
@@ -221,6 +224,8 @@ static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_lis
 		snprintf(prefix, sizeof(prefix), "BUG: ");
 
 	vreportf(prefix, fmt, params);
+	if (BUG_exit_code)
+		exit(BUG_exit_code);
 	abort();
 }
 
-- 
2.17.0.windows.1.36.gdf4ca5fb72a



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 2/4] run-command: use BUG() to report bugs, not die()
  2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
  2018-05-02  9:38           ` [PATCH v2 1/4] test-tool: help verifying BUG() code paths Johannes Schindelin
@ 2018-05-02  9:38           ` Johannes Schindelin
  2018-05-07  9:08             ` Jeff King
  2018-05-02  9:38           ` [PATCH v2 3/4] Replace all die("BUG: ...") calls by BUG() ones Johannes Schindelin
                             ` (2 subsequent siblings)
  4 siblings, 1 reply; 25+ messages in thread
From: Johannes Schindelin @ 2018-05-02  9:38 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Junio C Hamano, Jeff King, Johannes Sixt,
	Nguyễn Thái Ngọc Duy, Eric Sunshine

The slightly misleading name die_bug() of the function intended to
report a bug is actually called always, and only reports a bug if the
passed-in parameter `err` is non-zero.

It uses die_errno() to report the bug, to helpfully include the error
message corresponding to `err`.

However, as these messages indicate bugs, we really should use BUG().
And as BUG() is a macro to be able to report the exact file and line
number, we need to convert die_bug() to a macro instead of only
replacing the die_errno() by a call to BUG().

While at it, use a name more indicative of the purpose: CHECK_BUG().

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 run-command.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/run-command.c b/run-command.c
index 12c94c1dbe5..0ad6f135d5a 100644
--- a/run-command.c
+++ b/run-command.c
@@ -471,15 +471,12 @@ struct atfork_state {
 	sigset_t old;
 };
 
-#ifndef NO_PTHREADS
-static void bug_die(int err, const char *msg)
-{
-	if (err) {
-		errno = err;
-		die_errno("BUG: %s", msg);
-	}
-}
-#endif
+#define CHECK_BUG(err, msg) \
+	do { \
+		int e = (err); \
+		if (e) \
+			BUG("%s: %s", msg, strerror(e)); \
+	} while(0)
 
 static void atfork_prepare(struct atfork_state *as)
 {
@@ -491,9 +488,9 @@ static void atfork_prepare(struct atfork_state *as)
 	if (sigprocmask(SIG_SETMASK, &all, &as->old))
 		die_errno("sigprocmask");
 #else
-	bug_die(pthread_sigmask(SIG_SETMASK, &all, &as->old),
+	CHECK_BUG(pthread_sigmask(SIG_SETMASK, &all, &as->old),
 		"blocking all signals");
-	bug_die(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &as->cs),
+	CHECK_BUG(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &as->cs),
 		"disabling cancellation");
 #endif
 }
@@ -504,9 +501,9 @@ static void atfork_parent(struct atfork_state *as)
 	if (sigprocmask(SIG_SETMASK, &as->old, NULL))
 		die_errno("sigprocmask");
 #else
-	bug_die(pthread_setcancelstate(as->cs, NULL),
+	CHECK_BUG(pthread_setcancelstate(as->cs, NULL),
 		"re-enabling cancellation");
-	bug_die(pthread_sigmask(SIG_SETMASK, &as->old, NULL),
+	CHECK_BUG(pthread_sigmask(SIG_SETMASK, &as->old, NULL),
 		"restoring signal mask");
 #endif
 }
-- 
2.17.0.windows.1.36.gdf4ca5fb72a



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 3/4] Replace all die("BUG: ...") calls by BUG() ones
  2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
  2018-05-02  9:38           ` [PATCH v2 1/4] test-tool: help verifying BUG() code paths Johannes Schindelin
  2018-05-02  9:38           ` [PATCH v2 2/4] run-command: use BUG() to report bugs, not die() Johannes Schindelin
@ 2018-05-02  9:38           ` Johannes Schindelin
  2018-05-02  9:38           ` [PATCH v2 4/4] Convert remaining die*(BUG) messages Johannes Schindelin
  2018-05-07  9:01           ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Jeff King
  4 siblings, 0 replies; 25+ messages in thread
From: Johannes Schindelin @ 2018-05-02  9:38 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Junio C Hamano, Jeff King, Johannes Sixt,
	Nguyễn Thái Ngọc Duy, Eric Sunshine

In d8193743e08 (usage.c: add BUG() function, 2017-05-12), a new macro
was introduced to use for reporting bugs instead of die(). It was then
subsequently used to convert one single caller in 588a538ae55
(setup_git_env: convert die("BUG") to BUG(), 2017-05-12).

The cover letter of the patch series containing this patch
(cf 20170513032414.mfrwabt4hovujde2@sigill.intra.peff.net) is not
terribly clear why only one call site was converted, or what the plan
is for other, similar calls to die() to report bugs.

Let's just convert all remaining ones in one fell swoop.

This trick was performed by this invocation:

	sed -i 's/die("BUG: /BUG("/g' $(git grep -l 'die("BUG' \*.c)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 apply.c                          |  4 ++--
 archive-tar.c                    |  2 +-
 attr.c                           | 10 +++++-----
 blame.c                          |  2 +-
 builtin/am.c                     | 20 +++++++++----------
 builtin/branch.c                 |  2 +-
 builtin/cat-file.c               |  4 ++--
 builtin/clone.c                  |  2 +-
 builtin/commit.c                 |  2 +-
 builtin/config.c                 |  2 +-
 builtin/fast-export.c            |  2 +-
 builtin/fsck.c                   |  2 +-
 builtin/index-pack.c             |  4 ++--
 builtin/init-db.c                |  2 +-
 builtin/ls-files.c               |  2 +-
 builtin/notes.c                  |  8 ++++----
 builtin/pack-objects.c           |  4 ++--
 builtin/pull.c                   |  2 +-
 builtin/receive-pack.c           |  2 +-
 builtin/replace.c                |  2 +-
 builtin/update-index.c           |  2 +-
 bulk-checkin.c                   |  2 +-
 color.c                          |  4 ++--
 column.c                         |  2 +-
 config.c                         | 12 +++++------
 date.c                           |  2 +-
 diff.c                           | 12 +++++------
 dir-iterator.c                   |  2 +-
 grep.c                           | 16 +++++++--------
 http.c                           |  8 ++++----
 imap-send.c                      |  2 +-
 lockfile.c                       |  2 +-
 mailinfo.c                       |  2 +-
 merge-recursive.c                | 12 +++++------
 notes-merge.c                    |  4 ++--
 pack-bitmap-write.c              |  2 +-
 pack-bitmap.c                    |  6 +++---
 pack-objects.c                   |  2 +-
 packfile.c                       |  6 +++---
 pathspec.c                       | 10 +++++-----
 pkt-line.c                       |  2 +-
 prio-queue.c                     |  2 +-
 ref-filter.c                     |  4 ++--
 refs.c                           | 34 ++++++++++++++++----------------
 refs/files-backend.c             | 20 +++++++++----------
 refs/iterator.c                  |  6 +++---
 refs/packed-backend.c            | 16 +++++++--------
 refs/ref-cache.c                 |  2 +-
 remote.c                         |  2 +-
 revision.c                       |  4 ++--
 run-command.c                    | 10 +++++-----
 setup.c                          |  4 ++--
 sha1-lookup.c                    |  2 +-
 sha1-name.c                      |  4 ++--
 shallow.c                        |  6 +++---
 sigchain.c                       |  2 +-
 strbuf.c                         |  4 ++--
 submodule.c                      |  6 +++---
 t/helper/test-example-decorate.c | 16 +++++++--------
 tmp-objdir.c                     |  2 +-
 trailer.c                        |  6 +++---
 transport.c                      |  4 ++--
 unpack-trees.c                   |  2 +-
 worktree.c                       |  2 +-
 wrapper.c                        |  4 ++--
 wt-status.c                      | 20 +++++++++----------
 zlib.c                           |  4 ++--
 67 files changed, 190 insertions(+), 190 deletions(-)

diff --git a/apply.c b/apply.c
index 7e5792c996f..3866adbc97f 100644
--- a/apply.c
+++ b/apply.c
@@ -2375,7 +2375,7 @@ static void update_pre_post_images(struct image *preimage,
 	if (postlen
 	    ? postlen < new_buf - postimage->buf
 	    : postimage->len < new_buf - postimage->buf)
-		die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
+		BUG("caller miscounted postlen: asked %d, orig = %d, used = %d",
 		    (int)postlen, (int) postimage->len, (int)(new_buf - postimage->buf));
 
 	/* Fix the length of the whole thing */
@@ -3509,7 +3509,7 @@ static int load_current(struct apply_state *state,
 	unsigned mode = patch->new_mode;
 
 	if (!patch->is_new)
-		die("BUG: patch to %s is not a creation", patch->old_name);
+		BUG("patch to %s is not a creation", patch->old_name);
 
 	pos = cache_name_pos(name, strlen(name));
 	if (pos < 0)
diff --git a/archive-tar.c b/archive-tar.c
index 3563bcb9f26..61a1a2547cc 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -441,7 +441,7 @@ static int write_tar_filter_archive(const struct archiver *ar,
 	int r;
 
 	if (!ar->data)
-		die("BUG: tar-filter archiver called with no filter defined");
+		BUG("tar-filter archiver called with no filter defined");
 
 	strbuf_addstr(&cmd, ar->data);
 	if (args->compression_level >= 0)
diff --git a/attr.c b/attr.c
index 03a678fa9be..067fb9e0c08 100644
--- a/attr.c
+++ b/attr.c
@@ -157,7 +157,7 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
 
 	size = hashmap_get_size(&map->map);
 	if (size < check->all_attrs_nr)
-		die("BUG: interned attributes shouldn't be deleted");
+		BUG("interned attributes shouldn't be deleted");
 
 	/*
 	 * If the number of attributes in the global dictionary has increased
@@ -541,7 +541,7 @@ static void check_vector_remove(struct attr_check *check)
 			break;
 
 	if (i >= check_vector.nr)
-		die("BUG: no entry found");
+		BUG("no entry found");
 
 	/* shift entries over */
 	for (; i < check_vector.nr - 1; i++)
@@ -599,11 +599,11 @@ struct attr_check *attr_check_initl(const char *one, ...)
 		const struct git_attr *attr;
 		param = va_arg(params, const char *);
 		if (!param)
-			die("BUG: counted %d != ended at %d",
+			BUG("counted %d != ended at %d",
 			    check->nr, cnt);
 		attr = git_attr(param);
 		if (!attr)
-			die("BUG: %s: not a valid attribute name", param);
+			BUG("%s: not a valid attribute name", param);
 		check->items[cnt].attr = attr;
 	}
 	va_end(params);
@@ -714,7 +714,7 @@ void git_attr_set_direction(enum git_attr_direction new_direction,
 			    struct index_state *istate)
 {
 	if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)
-		die("BUG: non-INDEX attr direction in a bare repo");
+		BUG("non-INDEX attr direction in a bare repo");
 
 	if (new_direction != direction)
 		drop_all_attr_stacks();
diff --git a/blame.c b/blame.c
index 78c9808bd1a..89a1b11e922 100644
--- a/blame.c
+++ b/blame.c
@@ -1806,7 +1806,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
 			l->item = c;
 			if (add_decoration(&sb->revs->children,
 					   &c->parents->item->object, l))
-				die("BUG: not unique item in first-parent chain");
+				BUG("not unique item in first-parent chain");
 			c = c->parents->item;
 		}
 
diff --git a/builtin/am.c b/builtin/am.c
index d834f9e62b6..3dc2ef4259a 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -403,11 +403,11 @@ static void am_load(struct am_state *state)
 	struct strbuf sb = STRBUF_INIT;
 
 	if (read_state_file(&sb, state, "next", 1) < 0)
-		die("BUG: state file 'next' does not exist");
+		BUG("state file 'next' does not exist");
 	state->cur = strtol(sb.buf, NULL, 10);
 
 	if (read_state_file(&sb, state, "last", 1) < 0)
-		die("BUG: state file 'last' does not exist");
+		BUG("state file 'last' does not exist");
 	state->last = strtol(sb.buf, NULL, 10);
 
 	if (read_author_script(state) < 0)
@@ -986,7 +986,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
 	case PATCH_FORMAT_MBOXRD:
 		return split_mail_mbox(state, paths, keep_cr, 1);
 	default:
-		die("BUG: invalid patch_format");
+		BUG("invalid patch_format");
 	}
 	return -1;
 }
@@ -1041,7 +1041,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
 		str = "b";
 		break;
 	default:
-		die("BUG: invalid value for state->keep");
+		BUG("invalid value for state->keep");
 	}
 
 	write_state_text(state, "keep", str);
@@ -1058,7 +1058,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
 		str = "t";
 		break;
 	default:
-		die("BUG: invalid value for state->scissors");
+		BUG("invalid value for state->scissors");
 	}
 	write_state_text(state, "scissors", str);
 
@@ -1216,7 +1216,7 @@ static int parse_mail(struct am_state *state, const char *mail)
 		mi.keep_non_patch_brackets_in_subject = 1;
 		break;
 	default:
-		die("BUG: invalid value for state->keep");
+		BUG("invalid value for state->keep");
 	}
 
 	if (state->message_id)
@@ -1232,7 +1232,7 @@ static int parse_mail(struct am_state *state, const char *mail)
 		mi.use_scissors = 1;
 		break;
 	default:
-		die("BUG: invalid value for state->scissors");
+		BUG("invalid value for state->scissors");
 	}
 
 	mi.input = xfopen(mail, "r");
@@ -1463,7 +1463,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
 	int options = 0;
 
 	if (init_apply_state(&apply_state, NULL))
-		die("BUG: init_apply_state() failed");
+		BUG("init_apply_state() failed");
 
 	argv_array_push(&apply_opts, "apply");
 	argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
@@ -1489,7 +1489,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
 		apply_state.apply_verbosity = verbosity_silent;
 
 	if (check_apply_state(&apply_state, force_apply))
-		die("BUG: check_apply_state() failed");
+		BUG("check_apply_state() failed");
 
 	argv_array_push(&apply_paths, am_path(state, "patch"));
 
@@ -2407,7 +2407,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 		ret = show_patch(&state);
 		break;
 	default:
-		die("BUG: invalid resume value");
+		BUG("invalid resume value");
 	}
 
 	am_state_release(&state);
diff --git a/builtin/branch.c b/builtin/branch.c
index 5bd2a0dd489..1d4b3ce3d79 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -497,7 +497,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 
 	if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
 	    !skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
-		die("BUG: expected prefix missing for refs");
+		BUG("expected prefix missing for refs");
 	}
 
 	if (copy)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 2c46d257cd9..1cc3ccc4515 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -312,7 +312,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
 					die("could not convert '%s' %s",
 					    oid_to_hex(oid), data->rest);
 			} else
-				die("BUG: invalid cmdmode: %c", opt->cmdmode);
+				BUG("invalid cmdmode: %c", opt->cmdmode);
 			batch_write(opt, contents, size);
 			free(contents);
 		} else if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
@@ -387,7 +387,7 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
 			       (uintmax_t)strlen(obj_name), obj_name);
 			break;
 		default:
-			die("BUG: unknown get_sha1_with_context result %d\n",
+			BUG("unknown get_sha1_with_context result %d\n",
 			       result);
 			break;
 		}
diff --git a/builtin/clone.c b/builtin/clone.c
index 7df5932b855..918820c539c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -823,7 +823,7 @@ static void write_refspec_config(const char *src_ref_prefix,
 			} else if (remote_head_points_at) {
 				const char *head = remote_head_points_at->name;
 				if (!skip_prefix(head, "refs/heads/", &head))
-					die("BUG: remote HEAD points at non-head?");
+					BUG("remote HEAD points at non-head?");
 
 				strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
 						branch_top->buf, head);
diff --git a/builtin/commit.c b/builtin/commit.c
index 5571d4a3e2b..7b47d1b7fb3 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -495,7 +495,7 @@ static int is_a_merge(const struct commit *current_head)
 static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
 {
 	if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
-		die("BUG: unable to parse our own ident: %s", buf->buf);
+		BUG("unable to parse our own ident: %s", buf->buf);
 }
 
 static void export_one(const char *var, const char *s, const char *e, int hack)
diff --git a/builtin/config.c b/builtin/config.c
index 01169dd628b..c4f20332d74 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -309,7 +309,7 @@ static char *normalize_value(const char *key, const char *value)
 			return xstrdup(v ? "true" : "false");
 	}
 
-	die("BUG: cannot normalize type %d", types);
+	BUG("cannot normalize type %d", types);
 }
 
 static int get_color_found;
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index a15898d6417..116363f685c 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -517,7 +517,7 @@ static void anonymize_ident_line(const char **beg, const char **end)
 	/* skip "committer", "author", "tagger", etc */
 	end_of_header = strchr(*beg, ' ');
 	if (!end_of_header)
-		die("BUG: malformed line fed to anonymize_ident_line: %.*s",
+		BUG("malformed line fed to anonymize_ident_line: %.*s",
 		    (int)(*end - *beg), *beg);
 	end_of_header++;
 	strbuf_add(out, *beg, end_of_header - *beg);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 087360a6757..1ea414480a4 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -519,7 +519,7 @@ static struct object *parse_loose_object(const struct object_id *oid,
 		return NULL;
 
 	if (!contents && type != OBJ_BLOB)
-		die("BUG: read_loose_object streamed a non-blob");
+		BUG("read_loose_object streamed a non-blob");
 
 	obj = parse_object_buffer(oid, type, size, contents, &eaten);
 
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 78e66b99866..21f22e34952 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -866,7 +866,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
 			if (obj->type == OBJ_COMMIT) {
 				struct commit *commit = (struct commit *) obj;
 				if (detach_commit_buffer(commit, NULL) != data)
-					die("BUG: parse_object_buffer transmogrified our buffer");
+					BUG("parse_object_buffer transmogrified our buffer");
 			}
 			obj->flags |= FLAG_CHECKED;
 		}
@@ -1015,7 +1015,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 
 		if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
 					   base->obj->real_type))
-			die("BUG: child->real_type != OBJ_REF_DELTA");
+			BUG("child->real_type != OBJ_REF_DELTA");
 
 		resolve_delta(child, base, result);
 		if (base->ref_first == base->ref_last && base->ofs_last == -1)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 2542c5244e9..5a5844c1538 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -391,7 +391,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
 		else if (get_shared_repository() == PERM_EVERYBODY)
 			xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
 		else
-			die("BUG: invalid value for shared_repository");
+			BUG("invalid value for shared_repository");
 		git_config_set("core.sharedrepository", buf);
 		git_config_set("receive.denyNonFastforwards", "true");
 	}
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a71f6bd088a..967b2b3380d 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -166,7 +166,7 @@ static void show_killed_files(const struct index_state *istate,
 				 */
 				pos = index_name_pos(istate, ent->name, ent->len);
 				if (0 <= pos)
-					die("BUG: killed-file %.*s not found",
+					BUG("killed-file %.*s not found",
 						ent->len, ent->name);
 				pos = -pos - 1;
 				while (pos < istate->cache_nr &&
diff --git a/builtin/notes.c b/builtin/notes.c
index e5bf80eef1d..da279cdd349 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -461,7 +461,7 @@ static int add(int argc, const char **argv, const char *prefix)
 	if (d.buf.len || allow_empty) {
 		write_note_data(&d, &new_note);
 		if (add_note(t, &object, &new_note, combine_notes_overwrite))
-			die("BUG: combine_notes_overwrite failed");
+			BUG("combine_notes_overwrite failed");
 		commit_notes(t, "Notes added by 'git notes add'");
 	} else {
 		fprintf(stderr, _("Removing note for object %s\n"),
@@ -544,7 +544,7 @@ static int copy(int argc, const char **argv, const char *prefix)
 	}
 
 	if (add_note(t, &object, from_note, combine_notes_overwrite))
-		die("BUG: combine_notes_overwrite failed");
+		BUG("combine_notes_overwrite failed");
 	commit_notes(t, "Notes added by 'git notes copy'");
 out:
 	free_notes(t);
@@ -621,7 +621,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
 	if (d.buf.len || allow_empty) {
 		write_note_data(&d, &new_note);
 		if (add_note(t, &object, &new_note, combine_notes_overwrite))
-			die("BUG: combine_notes_overwrite failed");
+			BUG("combine_notes_overwrite failed");
 		logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
 	} else {
 		fprintf(stderr, _("Removing note for object %s\n"),
@@ -831,7 +831,7 @@ static int merge(int argc, const char **argv, const char *prefix)
 		const char *short_ref = NULL;
 
 		if (!skip_prefix(o.local_ref, "refs/notes/", &short_ref))
-			die("BUG: local ref %s is outside of refs/notes/",
+			BUG("local ref %s is outside of refs/notes/",
 			    o.local_ref);
 
 		strbuf_addf(&merge_key, "notes.%s.mergeStrategy", short_ref);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 4bdae5a1d8f..68de9134e1c 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1620,7 +1620,7 @@ static void break_delta_chains(struct object_entry *entry)
 		 * is a bug.
 		 */
 		if (cur->dfs_state != DFS_NONE)
-			die("BUG: confusing delta dfs state in first pass: %d",
+			BUG("confusing delta dfs state in first pass: %d",
 			    cur->dfs_state);
 
 		/*
@@ -1677,7 +1677,7 @@ static void break_delta_chains(struct object_entry *entry)
 		if (cur->dfs_state == DFS_DONE)
 			break;
 		else if (cur->dfs_state != DFS_ACTIVE)
-			die("BUG: confusing delta dfs state in second pass: %d",
+			BUG("confusing delta dfs state in second pass: %d",
 			    cur->dfs_state);
 
 		/*
diff --git a/builtin/pull.c b/builtin/pull.c
index 71aac5005e0..a886fa8ad4f 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -539,7 +539,7 @@ static int run_fetch(const char *repo, const char **refspecs)
 		argv_array_push(&args, repo);
 		argv_array_pushv(&args, refspecs);
 	} else if (*refspecs)
-		die("BUG: refspecs without repo?");
+		BUG("refspecs without repo?");
 	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
 	argv_array_clear(&args);
 	return ret;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 4b68a28e92e..2d719fa5117 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1378,7 +1378,7 @@ static void warn_if_skipped_connectivity_check(struct command *commands,
 		}
 	}
 	if (!checked_connectivity)
-		die("BUG: connectivity check skipped???");
+		BUG("connectivity check skipped???");
 }
 
 static void execute_commands_non_atomic(struct command *commands,
diff --git a/builtin/replace.c b/builtin/replace.c
index 935647be6bd..91a25394c00 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -501,6 +501,6 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
 		return list_replace_refs(argv[0], format);
 
 	default:
-		die("BUG: invalid cmdmode %d", (int)cmdmode);
+		BUG("invalid cmdmode %d", (int)cmdmode);
 	}
 }
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 10d070a76fb..ac19bbbb150 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -1164,7 +1164,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 		report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
 		break;
 	default:
-		die("BUG: bad untracked_cache value: %d", untracked_cache);
+		BUG("bad untracked_cache value: %d", untracked_cache);
 	}
 
 	if (fsmonitor > 0) {
diff --git a/bulk-checkin.c b/bulk-checkin.c
index de1f4040c78..f8a549dd7a4 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -230,7 +230,7 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
 		 * pack, and write into it.
 		 */
 		if (!idx)
-			die("BUG: should not happen");
+			BUG("should not happen");
 		hashfile_truncate(state->f, &checkpoint);
 		state->offset = checkpoint.offset;
 		finish_bulk_checkin(state);
diff --git a/color.c b/color.c
index f277e72e4ce..be1040005b4 100644
--- a/color.c
+++ b/color.c
@@ -174,7 +174,7 @@ static char *color_output(char *out, int len, const struct color *c, char type)
 		break;
 	case COLOR_ANSI:
 		if (len < 2)
-			die("BUG: color parsing ran out of space");
+			BUG("color parsing ran out of space");
 		*out++ = type;
 		*out++ = '0' + c->value;
 		break;
@@ -256,7 +256,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
 #undef OUT
 #define OUT(x) do { \
 	if (dst == end) \
-		die("BUG: color parsing ran out of space"); \
+		BUG("color parsing ran out of space"); \
 	*dst++ = (x); \
 } while(0)
 
diff --git a/column.c b/column.c
index 49ab85b7691..2165297608e 100644
--- a/column.c
+++ b/column.c
@@ -214,7 +214,7 @@ void print_columns(const struct string_list *list, unsigned int colopts,
 		display_table(list, colopts, &nopts);
 		break;
 	default:
-		die("BUG: invalid layout mode %d", COL_LAYOUT(colopts));
+		BUG("invalid layout mode %d", COL_LAYOUT(colopts));
 	}
 }
 
diff --git a/config.c b/config.c
index 62c56099bf8..cface6ab8aa 100644
--- a/config.c
+++ b/config.c
@@ -102,7 +102,7 @@ static int config_buf_ungetc(int c, struct config_source *conf)
 	if (conf->u.buf.pos > 0) {
 		conf->u.buf.pos--;
 		if (conf->u.buf.buf[conf->u.buf.pos] != c)
-			die("BUG: config_buf can only ungetc the same character");
+			BUG("config_buf can only ungetc the same character");
 		return c;
 	}
 
@@ -189,7 +189,7 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
 		strbuf_realpath(&path, cf->path, 1);
 		slash = find_last_dir_sep(path.buf);
 		if (!slash)
-			die("BUG: how is this possible?");
+			BUG("how is this possible?");
 		strbuf_splice(pat, 0, 1, path.buf, slash - path.buf);
 		prefix = slash - path.buf + 1 /* slash */;
 	} else if (!is_absolute_path(pat->buf))
@@ -1717,7 +1717,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
 	l_item->value_index = e->value_list.nr - 1;
 
 	if (!cf)
-		die("BUG: configset_add_value has no source");
+		BUG("configset_add_value has no source");
 	if (cf->name) {
 		kv_info->filename = strintern(cf->name);
 		kv_info->linenr = cf->linenr;
@@ -3006,7 +3006,7 @@ const char *current_config_origin_type(void)
 	else if(cf)
 		type = cf->origin_type;
 	else
-		die("BUG: current_config_origin_type called outside config callback");
+		BUG("current_config_origin_type called outside config callback");
 
 	switch (type) {
 	case CONFIG_ORIGIN_BLOB:
@@ -3020,7 +3020,7 @@ const char *current_config_origin_type(void)
 	case CONFIG_ORIGIN_CMDLINE:
 		return "command line";
 	default:
-		die("BUG: unknown config origin type");
+		BUG("unknown config origin type");
 	}
 }
 
@@ -3032,7 +3032,7 @@ const char *current_config_name(void)
 	else if (cf)
 		name = cf->name;
 	else
-		die("BUG: current_config_name called outside config callback");
+		BUG("current_config_name called outside config callback");
 	return name ? name : "";
 }
 
diff --git a/date.c b/date.c
index c3e673fd042..49f943e25b5 100644
--- a/date.c
+++ b/date.c
@@ -185,7 +185,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)
 {
 	static struct date_mode mode;
 	if (type == DATE_STRFTIME)
-		die("BUG: cannot create anonymous strftime date_mode struct");
+		BUG("cannot create anonymous strftime date_mode struct");
 	mode.type = type;
 	mode.local = 0;
 	return &mode;
diff --git a/diff.c b/diff.c
index 1289df4b1f9..9d8c7f60472 100644
--- a/diff.c
+++ b/diff.c
@@ -1184,7 +1184,7 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
 		fputs(o->stat_sep, o->file);
 		break;
 	default:
-		die("BUG: unknown diff symbol");
+		BUG("unknown diff symbol");
 	}
 	strbuf_release(&sb);
 }
@@ -1343,7 +1343,7 @@ static struct diff_tempfile *claim_diff_tempfile(void) {
 	for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
 		if (!diff_temp[i].name)
 			return diff_temp + i;
-	die("BUG: diff is failing to clean up its tempfiles");
+	BUG("diff is failing to clean up its tempfiles");
 }
 
 static void remove_tempfile(void)
@@ -3840,7 +3840,7 @@ static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev)
 		if (abbrev < 0)
 			abbrev = FALLBACK_DEFAULT_ABBREV;
 		if (abbrev > GIT_SHA1_HEXSZ)
-			die("BUG: oid abbreviation out of range: %d", abbrev);
+			BUG("oid abbreviation out of range: %d", abbrev);
 		if (abbrev)
 			hex[abbrev] = '\0';
 		return hex;
@@ -4334,7 +4334,7 @@ static int stat_opt(struct diff_options *options, const char **av)
 	int argcount = 1;
 
 	if (!skip_prefix(arg, "--stat", &arg))
-		die("BUG: stat option does not begin with --stat: %s", arg);
+		BUG("stat option does not begin with --stat: %s", arg);
 	end = (char *)arg;
 
 	switch (*arg) {
@@ -5519,7 +5519,7 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
 	struct diff_queue_struct *q = &diff_queued_diff;
 
 	if (WSEH_NEW & WS_RULE_MASK)
-		die("BUG: WS rules bit mask overlaps with diff symbol flags");
+		BUG("WS rules bit mask overlaps with diff symbol flags");
 
 	if (o->color_moved)
 		o->emitted_symbols = &esm;
@@ -6053,7 +6053,7 @@ size_t fill_textconv(struct userdiff_driver *driver,
 	}
 
 	if (!driver->textconv)
-		die("BUG: fill_textconv called with non-textconv driver");
+		BUG("fill_textconv called with non-textconv driver");
 
 	if (driver->textconv_cache && df->oid_valid) {
 		*outbuf = notes_cache_get(driver->textconv_cache,
diff --git a/dir-iterator.c b/dir-iterator.c
index 34182a9a1c1..f2dcd82fde9 100644
--- a/dir-iterator.c
+++ b/dir-iterator.c
@@ -188,7 +188,7 @@ struct dir_iterator *dir_iterator_begin(const char *path)
 	struct dir_iterator *dir_iterator = &iter->base;
 
 	if (!path || !*path)
-		die("BUG: empty path passed to dir_iterator_begin()");
+		BUG("empty path passed to dir_iterator_begin()");
 
 	strbuf_init(&iter->base.path, PATH_MAX);
 	strbuf_addstr(&iter->base.path, path);
diff --git a/grep.c b/grep.c
index 65b90c10a38..84f8054a3fd 100644
--- a/grep.c
+++ b/grep.c
@@ -404,7 +404,7 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
 			die("Couldn't allocate PCRE JIT stack");
 		pcre_assign_jit_stack(p->pcre1_extra_info, NULL, p->pcre1_jit_stack);
 	} else if (p->pcre1_jit_on != 0) {
-		die("BUG: The pcre1_jit_on variable should be 0 or 1, not %d",
+		BUG("The pcre1_jit_on variable should be 0 or 1, not %d",
 		    p->pcre1_jit_on);
 	}
 #endif
@@ -550,7 +550,7 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
 			die("Couldn't allocate PCRE2 match context");
 		pcre2_jit_stack_assign(p->pcre2_match_context, NULL, p->pcre2_jit_stack);
 	} else if (p->pcre2_jit_on != 0) {
-		die("BUG: The pcre2_jit_on variable should be 0 or 1, not %d",
+		BUG("The pcre2_jit_on variable should be 0 or 1, not %d",
 		    p->pcre1_jit_on);
 	}
 }
@@ -917,10 +917,10 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
 
 	for (p = opt->header_list; p; p = p->next) {
 		if (p->token != GREP_PATTERN_HEAD)
-			die("BUG: a non-header pattern in grep header list.");
+			BUG("a non-header pattern in grep header list.");
 		if (p->field < GREP_HEADER_FIELD_MIN ||
 		    GREP_HEADER_FIELD_MAX <= p->field)
-			die("BUG: unknown header field %d", p->field);
+			BUG("unknown header field %d", p->field);
 		compile_regexp(p, opt);
 	}
 
@@ -933,7 +933,7 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
 
 		h = compile_pattern_atom(&pp);
 		if (!h || pp != p->next)
-			die("BUG: malformed header expr");
+			BUG("malformed header expr");
 		if (!header_group[p->field]) {
 			header_group[p->field] = h;
 			continue;
@@ -1652,7 +1652,7 @@ static int fill_textconv_grep(struct userdiff_driver *driver,
 		fill_filespec(df, &null_oid, 0, 0100644);
 		break;
 	default:
-		die("BUG: attempt to textconv something without a path?");
+		BUG("attempt to textconv something without a path?");
 	}
 
 	/*
@@ -1748,7 +1748,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
 		case GREP_BINARY_TEXT:
 			break;
 		default:
-			die("BUG: unknown binary handling mode");
+			BUG("unknown binary handling mode");
 		}
 	}
 
@@ -2072,7 +2072,7 @@ static int grep_source_load(struct grep_source *gs)
 	case GREP_SOURCE_BUF:
 		return gs->buf ? 0 : -1;
 	}
-	die("BUG: invalid grep_source type to load");
+	BUG("invalid grep_source type to load");
 }
 
 void grep_source_load_driver(struct grep_source *gs)
diff --git a/http.c b/http.c
index 3034d10b680..ff60936bb0a 100644
--- a/http.c
+++ b/http.c
@@ -1855,7 +1855,7 @@ static int update_url_from_redirect(struct strbuf *base,
 		return 0;
 
 	if (!skip_prefix(asked, base->buf, &tail))
-		die("BUG: update_url_from_redirect: %s is not a superset of %s",
+		BUG("update_url_from_redirect: %s is not a superset of %s",
 		    asked, base->buf);
 
 	new_len = got->len;
@@ -1903,7 +1903,7 @@ static int http_request_reauth(const char *url,
 			strbuf_reset(result);
 			break;
 		default:
-			die("BUG: HTTP_KEEP_ERROR is only supported with strbufs");
+			BUG("HTTP_KEEP_ERROR is only supported with strbufs");
 		}
 	}
 
@@ -2114,7 +2114,7 @@ int finish_http_pack_request(struct http_pack_request *preq)
 	*lst = (*lst)->next;
 
 	if (!strip_suffix(preq->tmpfile, ".pack.temp", &len))
-		die("BUG: pack tmpfile does not end in .pack.temp?");
+		BUG("pack tmpfile does not end in .pack.temp?");
 	tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile);
 
 	argv_array_push(&ip.args, "index-pack");
@@ -2210,7 +2210,7 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
 		CURLcode c = curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE,
 						&slot->http_code);
 		if (c != CURLE_OK)
-			die("BUG: curl_easy_getinfo for HTTP code failed: %s",
+			BUG("curl_easy_getinfo for HTTP code failed: %s",
 				curl_easy_strerror(c));
 		if (slot->http_code >= 300)
 			return size;
diff --git a/imap-send.c b/imap-send.c
index 3573cbfb0fc..b4eb886e2a6 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -511,7 +511,7 @@ static int nfsnprintf(char *buf, int blen, const char *fmt, ...)
 
 	va_start(va, fmt);
 	if (blen <= 0 || (unsigned)(ret = vsnprintf(buf, blen, fmt, va)) >= (unsigned)blen)
-		die("BUG: buffer too small. Please report a bug.");
+		BUG("buffer too small. Please report a bug.");
 	va_end(va);
 	return ret;
 }
diff --git a/lockfile.c b/lockfile.c
index efcb7d7dfe3..8e8ab4f29f3 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -193,7 +193,7 @@ char *get_locked_file_path(struct lock_file *lk)
 	strbuf_addstr(&ret, get_tempfile_path(lk->tempfile));
 	if (ret.len <= LOCK_SUFFIX_LEN ||
 	    strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
-		die("BUG: get_locked_file_path() called for malformed lock object");
+		BUG("get_locked_file_path() called for malformed lock object");
 	/* remove ".lock": */
 	strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN);
 	return strbuf_detach(&ret, NULL);
diff --git a/mailinfo.c b/mailinfo.c
index d04142ccc76..3281a37d518 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -716,7 +716,7 @@ static void flush_inbody_header_accum(struct mailinfo *mi)
 	if (!mi->inbody_header_accum.len)
 		return;
 	if (!check_header(mi, &mi->inbody_header_accum, mi->s_hdr_data, 0))
-		die("BUG: inbody_header_accum, if not empty, must always contain a valid in-body header");
+		BUG("inbody_header_accum, if not empty, must always contain a valid in-body header");
 	strbuf_reset(&mi->inbody_header_accum);
 }
 
diff --git a/merge-recursive.c b/merge-recursive.c
index 0c0d48624da..6409d0770f2 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -318,7 +318,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
 				fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce),
 					(int)ce_namelen(ce), ce->name);
 		}
-		die("BUG: unmerged index entries in merge-recursive.c");
+		BUG("unmerged index entries in merge-recursive.c");
 	}
 
 	if (!active_cache_tree)
@@ -1060,7 +1060,7 @@ static int merge_file_1(struct merge_options *o,
 				break;
 			}
 		} else
-			die("BUG: unsupported object type in the tree");
+			BUG("unsupported object type in the tree");
 	}
 
 	return 0;
@@ -1462,7 +1462,7 @@ static int process_renames(struct merge_options *o,
 			const char *ren2_dst = ren2->pair->two->path;
 			enum rename_type rename_type;
 			if (strcmp(ren1_src, ren2_src) != 0)
-				die("BUG: ren1_src != ren2_src");
+				BUG("ren1_src != ren2_src");
 			ren2->dst_entry->processed = 1;
 			ren2->processed = 1;
 			if (strcmp(ren1_dst, ren2_dst) != 0) {
@@ -1496,7 +1496,7 @@ static int process_renames(struct merge_options *o,
 			ren2 = lookup->util;
 			ren2_dst = ren2->pair->two->path;
 			if (strcmp(ren1_dst, ren2_dst) != 0)
-				die("BUG: ren1_dst != ren2_dst");
+				BUG("ren1_dst != ren2_dst");
 
 			clean_merge = 0;
 			ren2->processed = 1;
@@ -1962,7 +1962,7 @@ static int process_entry(struct merge_options *o,
 		 */
 		remove_file(o, 1, path, !a_mode);
 	} else
-		die("BUG: fatal merge failure, shouldn't happen.");
+		BUG("fatal merge failure, shouldn't happen.");
 
 	return clean_merge;
 }
@@ -2040,7 +2040,7 @@ int merge_trees(struct merge_options *o,
 		for (i = 0; i < entries->nr; i++) {
 			struct stage_data *e = entries->items[i].util;
 			if (!e->processed)
-				die("BUG: unprocessed path??? %s",
+				BUG("unprocessed path??? %s",
 				    entries->items[i].string);
 		}
 
diff --git a/notes-merge.c b/notes-merge.c
index 8e0726a9418..720e24784c4 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -442,7 +442,7 @@ static int merge_one_change(struct notes_merge_options *o,
 			printf("Using remote notes for %s\n",
 						oid_to_hex(&p->obj));
 		if (add_note(t, &p->obj, &p->remote, combine_notes_overwrite))
-			die("BUG: combine_notes_overwrite failed");
+			BUG("combine_notes_overwrite failed");
 		return 0;
 	case NOTES_MERGE_RESOLVE_UNION:
 		if (o->verbosity >= 2)
@@ -490,7 +490,7 @@ static int merge_changes(struct notes_merge_options *o,
 			trace_printf("\t\t\tno local change, adopted remote\n");
 			if (add_note(t, &p->obj, &p->remote,
 				     combine_notes_overwrite))
-				die("BUG: combine_notes_overwrite failed");
+				BUG("combine_notes_overwrite failed");
 		} else {
 			/* need file-level merge between local and remote */
 			trace_printf("\t\t\tneed content-level merge\n");
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index 41ae27fb19a..3c7b5edda8a 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -474,7 +474,7 @@ static void write_selected_commits_v1(struct hashfile *f,
 			sha1_pos(stored->commit->object.oid.hash, index, index_nr, sha1_access);
 
 		if (commit_pos < 0)
-			die("BUG: trying to write commit not in index");
+			BUG("trying to write commit not in index");
 
 		hashwrite_be32(f, commit_pos);
 		hashwrite_u8(f, stored->xor_offset);
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 3f2dab340f6..a4837af0f4b 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -255,7 +255,7 @@ static char *pack_bitmap_filename(struct packed_git *p)
 	size_t len;
 
 	if (!strip_suffix(p->pack_name, ".pack", &len))
-		die("BUG: pack_name does not end in .pack");
+		BUG("pack_name does not end in .pack");
 	return xstrfmt("%.*s.bitmap", (int)len, p->pack_name);
 }
 
@@ -723,13 +723,13 @@ int prepare_bitmap_walk(struct rev_info *revs)
 		revs->ignore_missing_links = 0;
 
 		if (haves_bitmap == NULL)
-			die("BUG: failed to perform bitmap walk");
+			BUG("failed to perform bitmap walk");
 	}
 
 	wants_bitmap = find_objects(revs, wants, haves_bitmap);
 
 	if (!wants_bitmap)
-		die("BUG: failed to perform bitmap walk");
+		BUG("failed to perform bitmap walk");
 
 	if (haves_bitmap)
 		bitmap_and_not(wants_bitmap, haves_bitmap);
diff --git a/pack-objects.c b/pack-objects.c
index 9558d13834e..0acab27133c 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -58,7 +58,7 @@ static void rehash_objects(struct packing_data *pdata)
 						       &found);
 
 		if (found)
-			die("BUG: Duplicate object in hash");
+			BUG("Duplicate object in hash");
 
 		pdata->index[ix] = i + 1;
 		entry++;
diff --git a/packfile.c b/packfile.c
index 0bc67d0e009..9df0dab44da 100644
--- a/packfile.c
+++ b/packfile.c
@@ -188,7 +188,7 @@ int open_pack_index(struct packed_git *p)
 		return 0;
 
 	if (!strip_suffix(p->pack_name, ".pack", &len))
-		die("BUG: pack_name does not end in .pack");
+		BUG("pack_name does not end in .pack");
 	idx_name = xstrfmt("%.*s.idx", (int)len, p->pack_name);
 	ret = check_packed_git_idx(idx_name, p);
 	free(idx_name);
@@ -317,7 +317,7 @@ void close_all_packs(struct raw_object_store *o)
 
 	for (p = o->packed_git; p; p = p->next)
 		if (p->do_not_close)
-			die("BUG: want to close pack marked 'do-not-close'");
+			BUG("want to close pack marked 'do-not-close'");
 		else
 			close_pack(p);
 }
@@ -1561,7 +1561,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
 	case OBJ_OFS_DELTA:
 	case OBJ_REF_DELTA:
 		if (data)
-			die("BUG: unpack_entry: left loop at a valid delta");
+			BUG("unpack_entry: left loop at a valid delta");
 		break;
 	case OBJ_COMMIT:
 	case OBJ_TREE:
diff --git a/pathspec.c b/pathspec.c
index 82eb39cd679..a637a6d15c0 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -198,7 +198,7 @@ static void parse_pathspec_attr_match(struct pathspec_item *item, const char *va
 	}
 
 	if (item->attr_check->nr != item->attr_match_nr)
-		die("BUG: should have same number of entries");
+		BUG("should have same number of entries");
 
 	string_list_clear(&list, 0);
 }
@@ -422,7 +422,7 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
 
 	if (pathspec_prefix >= 0 &&
 	    (prefixlen || (prefix && *prefix)))
-		die("BUG: 'prefix' magic is supposed to be used at worktree's root");
+		BUG("'prefix' magic is supposed to be used at worktree's root");
 
 	if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
 		die(_("%s: 'literal' and 'glob' are incompatible"), elt);
@@ -545,7 +545,7 @@ void parse_pathspec(struct pathspec *pathspec,
 
 	if ((flags & PATHSPEC_PREFER_CWD) &&
 	    (flags & PATHSPEC_PREFER_FULL))
-		die("BUG: PATHSPEC_PREFER_CWD and PATHSPEC_PREFER_FULL are incompatible");
+		BUG("PATHSPEC_PREFER_CWD and PATHSPEC_PREFER_FULL are incompatible");
 
 	/* No arguments with prefix -> prefix pathspec */
 	if (!entry) {
@@ -553,7 +553,7 @@ void parse_pathspec(struct pathspec *pathspec,
 			return;
 
 		if (!(flags & PATHSPEC_PREFER_CWD))
-			die("BUG: PATHSPEC_PREFER_CWD requires arguments");
+			BUG("PATHSPEC_PREFER_CWD requires arguments");
 
 		pathspec->items = item = xcalloc(1, sizeof(*item));
 		item->match = xstrdup(prefix);
@@ -609,7 +609,7 @@ void parse_pathspec(struct pathspec *pathspec,
 
 	if (pathspec->magic & PATHSPEC_MAXDEPTH) {
 		if (flags & PATHSPEC_KEEP_ORDER)
-			die("BUG: PATHSPEC_MAXDEPTH_VALID and PATHSPEC_KEEP_ORDER are incompatible");
+			BUG("PATHSPEC_MAXDEPTH_VALID and PATHSPEC_KEEP_ORDER are incompatible");
 		QSORT(pathspec->items, pathspec->nr, pathspec_item_cmp);
 	}
 }
diff --git a/pkt-line.c b/pkt-line.c
index 2827ca772a3..cd3dab4025a 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -249,7 +249,7 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size,
 	ssize_t ret;
 
 	if (fd >= 0 && src_buf && *src_buf)
-		die("BUG: multiple sources given to packet_read");
+		BUG("multiple sources given to packet_read");
 
 	/* Read up to "size" bytes from our source, whatever it is. */
 	if (src_buf && *src_buf) {
diff --git a/prio-queue.c b/prio-queue.c
index 126d0967273..a0784518723 100644
--- a/prio-queue.c
+++ b/prio-queue.c
@@ -20,7 +20,7 @@ void prio_queue_reverse(struct prio_queue *queue)
 	int i, j;
 
 	if (queue->compare != NULL)
-		die("BUG: prio_queue_reverse() on non-LIFO queue");
+		BUG("prio_queue_reverse() on non-LIFO queue");
 	for (i = 0; i < (j = (queue->nr - 1) - i); i++)
 		swap(queue, i, j);
 }
diff --git a/ref-filter.c b/ref-filter.c
index ac82f9f21e1..0291feaf0db 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -751,7 +751,7 @@ static int grab_objectname(const char *name, const struct object_id *oid,
 			v->s = xstrdup(find_unique_abbrev(oid, atom->u.objectname.length));
 			return 1;
 		} else
-			die("BUG: unknown %%(objectname) option");
+			BUG("unknown %%(objectname) option");
 	}
 	return 0;
 }
@@ -1299,7 +1299,7 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
 		else
 			*s = "";
 	} else
-		die("BUG: unhandled RR_* enum");
+		BUG("unhandled RR_* enum");
 }
 
 char *get_head_description(void)
diff --git a/refs.c b/refs.c
index 8b7a77fe5ee..f7a577c0d60 100644
--- a/refs.c
+++ b/refs.c
@@ -944,10 +944,10 @@ void ref_transaction_free(struct ref_transaction *transaction)
 		/* OK */
 		break;
 	case REF_TRANSACTION_PREPARED:
-		die("BUG: free called on a prepared reference transaction");
+		BUG("free called on a prepared reference transaction");
 		break;
 	default:
-		die("BUG: unexpected reference transaction state");
+		BUG("unexpected reference transaction state");
 		break;
 	}
 
@@ -969,7 +969,7 @@ struct ref_update *ref_transaction_add_update(
 	struct ref_update *update;
 
 	if (transaction->state != REF_TRANSACTION_OPEN)
-		die("BUG: update called for transaction that is not open");
+		BUG("update called for transaction that is not open");
 
 	FLEX_ALLOC_STR(update, refname, refname);
 	ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
@@ -1019,7 +1019,7 @@ int ref_transaction_create(struct ref_transaction *transaction,
 			   struct strbuf *err)
 {
 	if (!new_oid || is_null_oid(new_oid))
-		die("BUG: create called without valid new_oid");
+		BUG("create called without valid new_oid");
 	return ref_transaction_update(transaction, refname, new_oid,
 				      &null_oid, flags, msg, err);
 }
@@ -1031,7 +1031,7 @@ int ref_transaction_delete(struct ref_transaction *transaction,
 			   struct strbuf *err)
 {
 	if (old_oid && is_null_oid(old_oid))
-		die("BUG: delete called with old_oid set to zeros");
+		BUG("delete called with old_oid set to zeros");
 	return ref_transaction_update(transaction, refname,
 				      &null_oid, old_oid,
 				      flags, msg, err);
@@ -1044,7 +1044,7 @@ int ref_transaction_verify(struct ref_transaction *transaction,
 			   struct strbuf *err)
 {
 	if (!old_oid)
-		die("BUG: verify called with old_oid set to NULL");
+		BUG("verify called with old_oid set to NULL");
 	return ref_transaction_update(transaction, refname,
 				      NULL, old_oid,
 				      flags, NULL, err);
@@ -1645,7 +1645,7 @@ static struct ref_store *ref_store_init(const char *gitdir,
 	struct ref_store *refs;
 
 	if (!be)
-		die("BUG: reference backend %s is unknown", be_name);
+		BUG("reference backend %s is unknown", be_name);
 
 	refs = be->init(gitdir, flags);
 	return refs;
@@ -1673,7 +1673,7 @@ static void register_ref_store_map(struct hashmap *map,
 		hashmap_init(map, ref_store_hash_cmp, NULL, 0);
 
 	if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
-		die("BUG: %s ref_store '%s' initialized twice", type, name);
+		BUG("%s ref_store '%s' initialized twice", type, name);
 }
 
 struct ref_store *get_submodule_ref_store(const char *submodule)
@@ -1819,7 +1819,7 @@ int ref_update_reject_duplicates(struct string_list *refnames,
 				    refnames->items[i].string);
 			return 1;
 		} else if (cmp > 0) {
-			die("BUG: ref_update_reject_duplicates() received unsorted list");
+			BUG("ref_update_reject_duplicates() received unsorted list");
 		}
 	}
 	return 0;
@@ -1835,13 +1835,13 @@ int ref_transaction_prepare(struct ref_transaction *transaction,
 		/* Good. */
 		break;
 	case REF_TRANSACTION_PREPARED:
-		die("BUG: prepare called twice on reference transaction");
+		BUG("prepare called twice on reference transaction");
 		break;
 	case REF_TRANSACTION_CLOSED:
-		die("BUG: prepare called on a closed reference transaction");
+		BUG("prepare called on a closed reference transaction");
 		break;
 	default:
-		die("BUG: unexpected reference transaction state");
+		BUG("unexpected reference transaction state");
 		break;
 	}
 
@@ -1868,10 +1868,10 @@ int ref_transaction_abort(struct ref_transaction *transaction,
 		ret = refs->be->transaction_abort(refs, transaction, err);
 		break;
 	case REF_TRANSACTION_CLOSED:
-		die("BUG: abort called on a closed reference transaction");
+		BUG("abort called on a closed reference transaction");
 		break;
 	default:
-		die("BUG: unexpected reference transaction state");
+		BUG("unexpected reference transaction state");
 		break;
 	}
 
@@ -1896,10 +1896,10 @@ int ref_transaction_commit(struct ref_transaction *transaction,
 		/* Fall through to finish. */
 		break;
 	case REF_TRANSACTION_CLOSED:
-		die("BUG: commit called on a closed reference transaction");
+		BUG("commit called on a closed reference transaction");
 		break;
 	default:
-		die("BUG: unexpected reference transaction state");
+		BUG("unexpected reference transaction state");
 		break;
 	}
 
@@ -1980,7 +1980,7 @@ int refs_verify_refname_available(struct ref_store *refs,
 	}
 
 	if (ok != ITER_DONE)
-		die("BUG: error while iterating over references");
+		BUG("error while iterating over references");
 
 	extra_refname = find_descendant_ref(dirname.buf, extras, skip);
 	if (extra_refname)
diff --git a/refs/files-backend.c b/refs/files-backend.c
index a92a2aa8213..332da47edd9 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -125,7 +125,7 @@ static void files_assert_main_repository(struct files_ref_store *refs,
 	if (refs->store_flags & REF_STORE_MAIN)
 		return;
 
-	die("BUG: operation %s only allowed for main ref store", caller);
+	BUG("operation %s only allowed for main ref store", caller);
 }
 
 /*
@@ -141,13 +141,13 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
 	struct files_ref_store *refs;
 
 	if (ref_store->be != &refs_be_files)
-		die("BUG: ref_store is type \"%s\" not \"files\" in %s",
+		BUG("ref_store is type \"%s\" not \"files\" in %s",
 		    ref_store->be->name, caller);
 
 	refs = (struct files_ref_store *)ref_store;
 
 	if ((refs->store_flags & required_flags) != required_flags)
-		die("BUG: operation %s requires abilities 0x%x, but only have 0x%x",
+		BUG("operation %s requires abilities 0x%x, but only have 0x%x",
 		    caller, required_flags, refs->store_flags);
 
 	return refs;
@@ -166,7 +166,7 @@ static void files_reflog_path(struct files_ref_store *refs,
 		strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
 		break;
 	default:
-		die("BUG: unknown ref type %d of ref %s",
+		BUG("unknown ref type %d of ref %s",
 		    ref_type(refname), refname);
 	}
 }
@@ -184,7 +184,7 @@ static void files_ref_path(struct files_ref_store *refs,
 		strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
 		break;
 	default:
-		die("BUG: unknown ref type %d of ref %s",
+		BUG("unknown ref type %d of ref %s",
 		    ref_type(refname), refname);
 	}
 }
@@ -2010,7 +2010,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
 
 	}
 	if (!ret && sb.len)
-		die("BUG: reverse reflog parser had leftover data");
+		BUG("reverse reflog parser had leftover data");
 
 	fclose(logfp);
 	strbuf_release(&sb);
@@ -2088,7 +2088,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
 static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,
 				   struct object_id *peeled)
 {
-	die("BUG: ref_iterator_peel() called for reflog_iterator");
+	BUG("ref_iterator_peel() called for reflog_iterator");
 }
 
 static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)
@@ -2873,7 +2873,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
 	assert(err);
 
 	if (transaction->state != REF_TRANSACTION_OPEN)
-		die("BUG: commit called for transaction that is not open");
+		BUG("commit called for transaction that is not open");
 
 	/* Fail if a refname appears more than once in the transaction: */
 	for (i = 0; i < transaction->nr; i++)
@@ -2899,7 +2899,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
 	 */
 	if (refs_for_each_rawref(&refs->base, ref_present,
 				 &affected_refnames))
-		die("BUG: initial ref transaction called with existing refs");
+		BUG("initial ref transaction called with existing refs");
 
 	packed_transaction = ref_store_transaction_begin(refs->packed_ref_store, err);
 	if (!packed_transaction) {
@@ -2912,7 +2912,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
 
 		if ((update->flags & REF_HAVE_OLD) &&
 		    !is_null_oid(&update->old_oid))
-			die("BUG: initial ref transaction with old_sha1 set");
+			BUG("initial ref transaction with old_sha1 set");
 		if (refs_verify_refname_available(&refs->base, update->refname,
 						  &affected_refnames, NULL,
 						  err)) {
diff --git a/refs/iterator.c b/refs/iterator.c
index bd35da4e622..2ac91ac3401 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -54,7 +54,7 @@ static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator)
 static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator,
 				   struct object_id *peeled)
 {
-	die("BUG: peel called for empty iterator");
+	BUG("peel called for empty iterator");
 }
 
 static int empty_ref_iterator_abort(struct ref_iterator *ref_iterator)
@@ -177,7 +177,7 @@ static int merge_ref_iterator_peel(struct ref_iterator *ref_iterator,
 		(struct merge_ref_iterator *)ref_iterator;
 
 	if (!iter->current) {
-		die("BUG: peel called before advance for merge iterator");
+		BUG("peel called before advance for merge iterator");
 	}
 	return ref_iterator_peel(*iter->current, peeled);
 }
@@ -338,7 +338,7 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
 			 * trimming, report it as a bug:
 			 */
 			if (strlen(iter->iter0->refname) <= iter->trim)
-				die("BUG: attempt to trim too many characters");
+				BUG("attempt to trim too many characters");
 			iter->base.refname = iter->iter0->refname + iter->trim;
 		} else {
 			iter->base.refname = iter->iter0->refname;
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 369c34f886f..cec3fb9e00f 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -221,13 +221,13 @@ static struct packed_ref_store *packed_downcast(struct ref_store *ref_store,
 	struct packed_ref_store *refs;
 
 	if (ref_store->be != &refs_be_packed)
-		die("BUG: ref_store is type \"%s\" not \"packed\" in %s",
+		BUG("ref_store is type \"%s\" not \"packed\" in %s",
 		    ref_store->be->name, caller);
 
 	refs = (struct packed_ref_store *)ref_store;
 
 	if ((refs->store_flags & required_flags) != required_flags)
-		die("BUG: unallowed operation (%s), requires %x, has %x\n",
+		BUG("unallowed operation (%s), requires %x, has %x\n",
 		    caller, required_flags, refs->store_flags);
 
 	return refs;
@@ -1036,7 +1036,7 @@ void packed_refs_unlock(struct ref_store *ref_store)
 			"packed_refs_unlock");
 
 	if (!is_lock_file_locked(&refs->lock))
-		die("BUG: packed_refs_unlock() called when not locked");
+		BUG("packed_refs_unlock() called when not locked");
 	rollback_lock_file(&refs->lock);
 }
 
@@ -1089,7 +1089,7 @@ static int write_with_updates(struct packed_ref_store *refs,
 	char *packed_refs_path;
 
 	if (!is_lock_file_locked(&refs->lock))
-		die("BUG: write_with_updates() called while unlocked");
+		BUG("write_with_updates() called while unlocked");
 
 	/*
 	 * If packed-refs is a symlink, we want to overwrite the
@@ -1563,21 +1563,21 @@ static int packed_create_symref(struct ref_store *ref_store,
 			       const char *refname, const char *target,
 			       const char *logmsg)
 {
-	die("BUG: packed reference store does not support symrefs");
+	BUG("packed reference store does not support symrefs");
 }
 
 static int packed_rename_ref(struct ref_store *ref_store,
 			    const char *oldrefname, const char *newrefname,
 			    const char *logmsg)
 {
-	die("BUG: packed reference store does not support renaming references");
+	BUG("packed reference store does not support renaming references");
 }
 
 static int packed_copy_ref(struct ref_store *ref_store,
 			   const char *oldrefname, const char *newrefname,
 			   const char *logmsg)
 {
-	die("BUG: packed reference store does not support copying references");
+	BUG("packed reference store does not support copying references");
 }
 
 static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store)
@@ -1610,7 +1610,7 @@ static int packed_create_reflog(struct ref_store *ref_store,
 			       const char *refname, int force_create,
 			       struct strbuf *err)
 {
-	die("BUG: packed reference store does not support reflogs");
+	BUG("packed reference store does not support reflogs");
 }
 
 static int packed_delete_reflog(struct ref_store *ref_store,
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index e90bd3e727f..9b110c8494f 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -23,7 +23,7 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
 	dir = &entry->u.subdir;
 	if (entry->flag & REF_INCOMPLETE) {
 		if (!dir->cache->fill_ref_dir)
-			die("BUG: incomplete ref_store without fill_ref_dir function");
+			BUG("incomplete ref_store without fill_ref_dir function");
 
 		dir->cache->fill_ref_dir(dir->cache->ref_store, dir, entry->name);
 		entry->flag &= ~REF_INCOMPLETE;
diff --git a/remote.c b/remote.c
index 91eb010ca98..63c41787882 100644
--- a/remote.c
+++ b/remote.c
@@ -1819,7 +1819,7 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
 		}
 	}
 
-	die("BUG: unhandled push situation");
+	BUG("unhandled push situation");
 }
 
 const char *branch_get_push(struct branch *branch, struct strbuf *err)
diff --git a/revision.c b/revision.c
index b42c836d7a6..67f8e74cbb3 100644
--- a/revision.c
+++ b/revision.c
@@ -2107,7 +2107,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->ignore_missing = 1;
 	} else if (!strcmp(arg, "--exclude-promisor-objects")) {
 		if (fetch_if_missing)
-			die("BUG: exclude_promisor_objects can only be used when fetch_if_missing is 0");
+			BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
 		revs->exclude_promisor_objects = 1;
 	} else {
 		int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
@@ -2173,7 +2173,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
 		 * supported right now, so stick to single worktree.
 		 */
 		if (!revs->single_worktree)
-			die("BUG: --single-worktree cannot be used together with submodule");
+			BUG("--single-worktree cannot be used together with submodule");
 		refs = get_submodule_ref_store(submodule);
 	} else
 		refs = get_main_ref_store();
diff --git a/run-command.c b/run-command.c
index 0ad6f135d5a..84b883c2132 100644
--- a/run-command.c
+++ b/run-command.c
@@ -245,7 +245,7 @@ int sane_execvp(const char *file, char * const argv[])
 static const char **prepare_shell_cmd(struct argv_array *out, const char **argv)
 {
 	if (!argv[0])
-		die("BUG: shell command is empty");
+		BUG("shell command is empty");
 
 	if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
 #ifndef GIT_WINDOWS_NATIVE
@@ -383,7 +383,7 @@ static void child_err_spew(struct child_process *cmd, struct child_err *cerr)
 static void prepare_cmd(struct argv_array *out, const struct child_process *cmd)
 {
 	if (!cmd->argv[0])
-		die("BUG: command is empty");
+		BUG("command is empty");
 
 	/*
 	 * Add SHELL_PATH so in the event exec fails with ENOEXEC we can
@@ -964,7 +964,7 @@ int run_command(struct child_process *cmd)
 	int code;
 
 	if (cmd->out < 0 || cmd->err < 0)
-		die("BUG: run_command with a pipe can cause deadlock");
+		BUG("run_command with a pipe can cause deadlock");
 
 	code = start_command(cmd);
 	if (code)
@@ -1554,7 +1554,7 @@ static void pp_init(struct parallel_processes *pp,
 
 	pp->data = data;
 	if (!get_next_task)
-		die("BUG: you need to specify a get_next_task function");
+		BUG("you need to specify a get_next_task function");
 	pp->get_next_task = get_next_task;
 
 	pp->start_failure = start_failure ? start_failure : default_start_failure;
@@ -1616,7 +1616,7 @@ static int pp_start_one(struct parallel_processes *pp)
 		if (pp->children[i].state == GIT_CP_FREE)
 			break;
 	if (i == pp->max_processes)
-		die("BUG: bookkeeping is hard");
+		BUG("bookkeeping is hard");
 
 	code = pp->get_next_task(&pp->children[i].process,
 				 &pp->children[i].err,
diff --git a/setup.c b/setup.c
index 3e03d442b6f..b24c811c1c3 100644
--- a/setup.c
+++ b/setup.c
@@ -539,7 +539,7 @@ void read_gitfile_error_die(int error_code, const char *path, const char *dir)
 	case READ_GITFILE_ERR_NOT_A_REPO:
 		die(_("not a git repository: %s"), dir);
 	default:
-		die("BUG: unknown error code");
+		BUG("unknown error code");
 	}
 }
 
@@ -1086,7 +1086,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
 		      "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
 		    dir.buf);
 	default:
-		die("BUG: unhandled setup_git_directory_1() result");
+		BUG("unhandled setup_git_directory_1() result");
 	}
 
 	if (prefix)
diff --git a/sha1-lookup.c b/sha1-lookup.c
index 8d0b1db3e27..796ab68da83 100644
--- a/sha1-lookup.c
+++ b/sha1-lookup.c
@@ -81,7 +81,7 @@ int sha1_pos(const unsigned char *sha1, void *table, size_t nr,
 				mi = (nr - 1) * (miv - lov) / (hiv - lov);
 				if (lo <= mi && mi < hi)
 					break;
-				die("BUG: assertion failed in binary search");
+				BUG("assertion failed in binary search");
 			}
 		}
 	}
diff --git a/sha1-name.c b/sha1-name.c
index 5b93bf8da36..60d04bf74e1 100644
--- a/sha1-name.c
+++ b/sha1-name.c
@@ -384,7 +384,7 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,
 		return -1;
 
 	if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
-		die("BUG: multiple get_short_oid disambiguator flags");
+		BUG("multiple get_short_oid disambiguator flags");
 
 	if (flags & GET_OID_COMMIT)
 		ds.fn = disambiguate_commit_only;
@@ -1729,6 +1729,6 @@ void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
 int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)
 {
 	if (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)
-		die("BUG: incompatible flags for get_sha1_with_context");
+		BUG("incompatible flags for get_sha1_with_context");
 	return get_oid_with_context_1(str, flags, NULL, oid, oc);
 }
diff --git a/shallow.c b/shallow.c
index df4d44ea7a3..c7b6b3d9d8a 100644
--- a/shallow.c
+++ b/shallow.c
@@ -20,7 +20,7 @@ static char *alternate_shallow_file;
 void set_alternate_shallow_file(const char *path, int override)
 {
 	if (is_shallow != -1)
-		die("BUG: is_repository_shallow must not be called before set_alternate_shallow_file");
+		BUG("is_repository_shallow must not be called before set_alternate_shallow_file");
 	if (alternate_shallow_file && !override)
 		return;
 	free(alternate_shallow_file);
@@ -218,7 +218,7 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av,
 static void check_shallow_file_for_update(void)
 {
 	if (is_shallow == -1)
-		die("BUG: shallow must be initialized by now");
+		BUG("shallow must be initialized by now");
 
 	if (!stat_validity_check(&shallow_stat, git_path_shallow()))
 		die("shallow file has changed since we read it");
@@ -446,7 +446,7 @@ static uint32_t *paint_alloc(struct paint_info *info)
 	void *p;
 	if (!info->pool_count || size > info->end - info->free) {
 		if (size > POOL_SIZE)
-			die("BUG: pool size too small for %d in paint_alloc()",
+			BUG("pool size too small for %d in paint_alloc()",
 			    size);
 		info->pool_count++;
 		REALLOC_ARRAY(info->pools, info->pool_count);
diff --git a/sigchain.c b/sigchain.c
index 2ac43bbd282..022677b6aba 100644
--- a/sigchain.c
+++ b/sigchain.c
@@ -13,7 +13,7 @@ static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
 static void check_signum(int sig)
 {
 	if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
-		die("BUG: signal out of range: %d", sig);
+		BUG("signal out of range: %d", sig);
 }
 
 int sigchain_push(int sig, sigchain_fun f)
diff --git a/strbuf.c b/strbuf.c
index 43a840c67b3..2954622c103 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -309,12 +309,12 @@ void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
 	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
 	va_end(cp);
 	if (len < 0)
-		die("BUG: your vsnprintf is broken (returned %d)", len);
+		BUG("your vsnprintf is broken (returned %d)", len);
 	if (len > strbuf_avail(sb)) {
 		strbuf_grow(sb, len);
 		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
 		if (len > strbuf_avail(sb))
-			die("BUG: your vsnprintf is broken (insatiable)");
+			BUG("your vsnprintf is broken (insatiable)");
 	}
 	strbuf_setlen(sb, sb->len + len);
 }
diff --git a/submodule.c b/submodule.c
index 9a50168b237..733db441714 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1398,7 +1398,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
 		    buf.buf[0] == '2') {
 			/* T = line type, XY = status, SSSS = submodule state */
 			if (buf.len < strlen("T XY SSSS"))
-				die("BUG: invalid status --porcelain=2 line %s",
+				BUG("invalid status --porcelain=2 line %s",
 				    buf.buf);
 
 			if (buf.buf[5] == 'S' && buf.buf[8] == 'U')
@@ -1607,7 +1607,7 @@ int submodule_move_head(const char *path,
 	sub = submodule_from_path(&null_oid, path);
 
 	if (!sub)
-		die("BUG: could not get submodule information for '%s'", path);
+		BUG("could not get submodule information for '%s'", path);
 
 	if (old_head && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) {
 		/* Check if the submodule has a dirty index. */
@@ -1965,7 +1965,7 @@ void absorb_git_dir_into_superproject(const char *prefix,
 		struct strbuf sb = STRBUF_INIT;
 
 		if (flags & ~ABSORB_GITDIR_RECURSE_SUBMODULES)
-			die("BUG: we don't know how to pass the flags down?");
+			BUG("we don't know how to pass the flags down?");
 
 		strbuf_addstr(&sb, get_super_prefix_or_empty());
 		strbuf_addstr(&sb, path);
diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c
index 081115bf8eb..a20a6161e4f 100644
--- a/t/helper/test-example-decorate.c
+++ b/t/helper/test-example-decorate.c
@@ -30,10 +30,10 @@ int cmd__example_decorate(int argc, const char **argv)
 	two = lookup_unknown_object(two_oid.hash);
 	ret = add_decoration(&n, one, &decoration_a);
 	if (ret)
-		die("BUG: when adding a brand-new object, NULL should be returned");
+		BUG("when adding a brand-new object, NULL should be returned");
 	ret = add_decoration(&n, two, NULL);
 	if (ret)
-		die("BUG: when adding a brand-new object, NULL should be returned");
+		BUG("when adding a brand-new object, NULL should be returned");
 
 	/*
 	 * When re-adding an already existing object, the old decoration is
@@ -41,10 +41,10 @@ int cmd__example_decorate(int argc, const char **argv)
 	 */
 	ret = add_decoration(&n, one, NULL);
 	if (ret != &decoration_a)
-		die("BUG: when readding an already existing object, existing decoration should be returned");
+		BUG("when readding an already existing object, existing decoration should be returned");
 	ret = add_decoration(&n, two, &decoration_b);
 	if (ret)
-		die("BUG: when readding an already existing object, existing decoration should be returned");
+		BUG("when readding an already existing object, existing decoration should be returned");
 
 	/*
 	 * Lookup returns the added declarations, or NULL if the object was
@@ -52,14 +52,14 @@ int cmd__example_decorate(int argc, const char **argv)
 	 */
 	ret = lookup_decoration(&n, one);
 	if (ret)
-		die("BUG: lookup should return added declaration");
+		BUG("lookup should return added declaration");
 	ret = lookup_decoration(&n, two);
 	if (ret != &decoration_b)
-		die("BUG: lookup should return added declaration");
+		BUG("lookup should return added declaration");
 	three = lookup_unknown_object(three_oid.hash);
 	ret = lookup_decoration(&n, three);
 	if (ret)
-		die("BUG: lookup for unknown object should return NULL");
+		BUG("lookup for unknown object should return NULL");
 
 	/*
 	 * The user can also loop through all entries.
@@ -69,7 +69,7 @@ int cmd__example_decorate(int argc, const char **argv)
 			objects_noticed++;
 	}
 	if (objects_noticed != 2)
-		die("BUG: should have 2 objects");
+		BUG("should have 2 objects");
 
 	return 0;
 }
diff --git a/tmp-objdir.c b/tmp-objdir.c
index fea3f55545c..91c00567f4d 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -127,7 +127,7 @@ struct tmp_objdir *tmp_objdir_create(void)
 	struct tmp_objdir *t;
 
 	if (the_tmp_objdir)
-		die("BUG: only one tmp_objdir can be used at a time");
+		BUG("only one tmp_objdir can be used at a time");
 
 	t = xmalloc(sizeof(*t));
 	strbuf_init(&t->path, 0);
diff --git a/trailer.c b/trailer.c
index c508c9b7521..4e309460d13 100644
--- a/trailer.c
+++ b/trailer.c
@@ -298,7 +298,7 @@ static void apply_arg_if_exists(struct trailer_item *in_tok,
 			free_arg_item(arg_tok);
 		break;
 	default:
-		die("BUG: trailer.c: unhandled value %d",
+		BUG("trailer.c: unhandled value %d",
 		    arg_tok->conf.if_exists);
 	}
 }
@@ -323,7 +323,7 @@ static void apply_arg_if_missing(struct list_head *head,
 			list_add(&to_add->list, head);
 		break;
 	default:
-		die("BUG: trailer.c: unhandled value %d",
+		BUG("trailer.c: unhandled value %d",
 		    arg_tok->conf.if_missing);
 	}
 }
@@ -557,7 +557,7 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)
 			warning(_("unknown value '%s' for key '%s'"), value, conf_key);
 		break;
 	default:
-		die("BUG: trailer.c: unhandled type %d", type);
+		BUG("trailer.c: unhandled type %d", type);
 	}
 	return 0;
 }
diff --git a/transport.c b/transport.c
index 94eccf29aa3..969645ccb13 100644
--- a/transport.c
+++ b/transport.c
@@ -636,7 +636,7 @@ void transport_take_over(struct transport *transport,
 	struct git_transport_data *data;
 
 	if (!transport->smart_options)
-		die("BUG: taking over transport requires non-NULL "
+		BUG("taking over transport requires non-NULL "
 		    "smart_options field.");
 
 	data = xcalloc(1, sizeof(*data));
@@ -761,7 +761,7 @@ int is_transport_allowed(const char *type, int from_user)
 		return from_user;
 	}
 
-	die("BUG: invalid protocol_allow_config type");
+	BUG("invalid protocol_allow_config type");
 }
 
 void transport_check_allowed(const char *type)
diff --git a/unpack-trees.c b/unpack-trees.c
index e73745051e5..4239dfd285e 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -398,7 +398,7 @@ static int check_updates(struct unpack_trees_options *o)
 
 		if (ce->ce_flags & CE_UPDATE) {
 			if (ce->ce_flags & CE_WT_REMOVE)
-				die("BUG: both update and delete flags are set on %s",
+				BUG("both update and delete flags are set on %s",
 				    ce->name);
 			display_progress(progress, ++cnt);
 			ce->ce_flags &= ~CE_UPDATE;
diff --git a/worktree.c b/worktree.c
index 28989cf06ef..97cda5f97bb 100644
--- a/worktree.c
+++ b/worktree.c
@@ -338,7 +338,7 @@ void update_worktree_location(struct worktree *wt, const char *path_)
 	struct strbuf path = STRBUF_INIT;
 
 	if (is_main_worktree(wt))
-		die("BUG: can't relocate main worktree");
+		BUG("can't relocate main worktree");
 
 	strbuf_realpath(&path, path_, 1);
 	if (fspathcmp(wt->path, path.buf)) {
diff --git a/wrapper.c b/wrapper.c
index 1fd5e33ea8f..e4fa9d84cd0 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -643,9 +643,9 @@ int xsnprintf(char *dst, size_t max, const char *fmt, ...)
 	va_end(ap);
 
 	if (len < 0)
-		die("BUG: your snprintf is broken");
+		BUG("your snprintf is broken");
 	if (len >= max)
-		die("BUG: attempt to snprintf into too-small buffer");
+		BUG("attempt to snprintf into too-small buffer");
 	return len;
 }
 
diff --git a/wt-status.c b/wt-status.c
index 50815e5faff..26d037610ee 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -264,7 +264,7 @@ static const char *wt_status_unmerged_status_string(int stagemask)
 	case 7:
 		return _("both modified:");
 	default:
-		die("BUG: unhandled unmerged status %x", stagemask);
+		BUG("unhandled unmerged status %x", stagemask);
 	}
 }
 
@@ -377,7 +377,7 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
 		status = d->worktree_status;
 		break;
 	default:
-		die("BUG: unhandled change_type %d in wt_longstatus_print_change_data",
+		BUG("unhandled change_type %d in wt_longstatus_print_change_data",
 		    change_type);
 	}
 
@@ -395,7 +395,7 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
 	status_printf(s, color(WT_STATUS_HEADER, s), "\t");
 	what = wt_status_diff_status_string(status);
 	if (!what)
-		die("BUG: unhandled diff status %c", status);
+		BUG("unhandled diff status %c", status);
 	len = label_width - utf8_strwidth(what);
 	assert(len >= 0);
 	if (one_name != two_name)
@@ -470,7 +470,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
 		case DIFF_STATUS_COPIED:
 		case DIFF_STATUS_RENAMED:
 			if (d->rename_status)
-				die("BUG: multiple renames on the same target? how?");
+				BUG("multiple renames on the same target? how?");
 			d->rename_source = xstrdup(p->one->path);
 			d->rename_score = p->score * 100 / MAX_SCORE;
 			d->rename_status = p->status;
@@ -484,7 +484,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
 			break;
 
 		default:
-			die("BUG: unhandled diff-files status '%c'", p->status);
+			BUG("unhandled diff-files status '%c'", p->status);
 			break;
 		}
 
@@ -547,7 +547,7 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
 		case DIFF_STATUS_COPIED:
 		case DIFF_STATUS_RENAMED:
 			if (d->rename_status)
-				die("BUG: multiple renames on the same target? how?");
+				BUG("multiple renames on the same target? how?");
 			d->rename_source = xstrdup(p->one->path);
 			d->rename_score = p->score * 100 / MAX_SCORE;
 			d->rename_status = p->status;
@@ -569,7 +569,7 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
 			break;
 
 		default:
-			die("BUG: unhandled diff-index status '%c'", p->status);
+			BUG("unhandled diff-index status '%c'", p->status);
 			break;
 		}
 	}
@@ -2158,7 +2158,7 @@ static void wt_porcelain_v2_print_unmerged_entry(
 	case 6: key = "AA"; break; /* both added */
 	case 7: key = "UU"; break; /* both modified */
 	default:
-		die("BUG: unhandled unmerged status %x", d->stagemask);
+		BUG("unhandled unmerged status %x", d->stagemask);
 	}
 
 	/*
@@ -2185,7 +2185,7 @@ static void wt_porcelain_v2_print_unmerged_entry(
 		sum |= (1 << (stage - 1));
 	}
 	if (sum != d->stagemask)
-		die("BUG: observed stagemask 0x%x != expected stagemask 0x%x", sum, d->stagemask);
+		BUG("observed stagemask 0x%x != expected stagemask 0x%x", sum, d->stagemask);
 
 	if (s->null_termination)
 		path_index = it->string;
@@ -2289,7 +2289,7 @@ void wt_status_print(struct wt_status *s)
 		wt_porcelain_v2_print(s);
 		break;
 	case STATUS_FORMAT_UNSPECIFIED:
-		die("BUG: finalize_deferred_config() should have been called");
+		BUG("finalize_deferred_config() should have been called");
 		break;
 	case STATUS_FORMAT_NONE:
 	case STATUS_FORMAT_LONG:
diff --git a/zlib.c b/zlib.c
index 4223f1a8c57..d594cba3fc9 100644
--- a/zlib.c
+++ b/zlib.c
@@ -52,9 +52,9 @@ static void zlib_post_call(git_zstream *s)
 	bytes_consumed = s->z.next_in - s->next_in;
 	bytes_produced = s->z.next_out - s->next_out;
 	if (s->z.total_out != s->total_out + bytes_produced)
-		die("BUG: total_out mismatch");
+		BUG("total_out mismatch");
 	if (s->z.total_in != s->total_in + bytes_consumed)
-		die("BUG: total_in mismatch");
+		BUG("total_in mismatch");
 
 	s->total_out = s->z.total_out;
 	s->total_in = s->z.total_in;
-- 
2.17.0.windows.1.36.gdf4ca5fb72a



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 4/4] Convert remaining die*(BUG) messages
  2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
                             ` (2 preceding siblings ...)
  2018-05-02  9:38           ` [PATCH v2 3/4] Replace all die("BUG: ...") calls by BUG() ones Johannes Schindelin
@ 2018-05-02  9:38           ` Johannes Schindelin
  2018-05-07  9:01           ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Jeff King
  4 siblings, 0 replies; 25+ messages in thread
From: Johannes Schindelin @ 2018-05-02  9:38 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Junio C Hamano, Jeff King, Johannes Sixt,
	Nguyễn Thái Ngọc Duy, Eric Sunshine

These were not caught by the previous commit, as they did not match the
regular expression.

While at it, remove the localization from one instance: we never want
BUG() messages to be translated, as they target Git developers, not the
end user (hence it would be quite unhelpful to not only burden the
translators, but then even end up with a bug report in a language that
no core Git contributor understands).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 git-compat-util.h     | 2 +-
 pathspec.c            | 2 +-
 submodule.c           | 2 +-
 vcs-svn/fast_export.c | 6 ++++--
 4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 07e383257b4..3a7216f5313 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1052,7 +1052,7 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
 
 #define QSORT_S(base, n, compar, ctx) do {			\
 	if (qsort_s((base), (n), sizeof(*(base)), compar, ctx))	\
-		die("BUG: qsort_s() failed");			\
+		BUG("qsort_s() failed");			\
 } while (0)
 
 #ifndef REG_STARTEND
diff --git a/pathspec.c b/pathspec.c
index a637a6d15c0..27cd6067860 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -486,7 +486,7 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
 	/* sanity checks, pathspec matchers assume these are sane */
 	if (item->nowildcard_len > item->len ||
 	    item->prefix         > item->len) {
-		die ("BUG: error initializing pathspec_item");
+		BUG("error initializing pathspec_item");
 	}
 }
 
diff --git a/submodule.c b/submodule.c
index 733db441714..c282fa8fe51 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2043,7 +2043,7 @@ const char *get_superproject_working_tree(void)
 
 		if (super_sub_len > cwd_len ||
 		    strcmp(&cwd[cwd_len - super_sub_len], super_sub))
-			die (_("BUG: returned path string doesn't match cwd?"));
+			BUG("returned path string doesn't match cwd?");
 
 		super_wt = xstrdup(cwd);
 		super_wt[cwd_len - super_sub_len] = '\0';
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 3fd047a8b82..b5b8913cb0f 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -320,7 +320,8 @@ const char *fast_export_read_path(const char *path, uint32_t *mode_out)
 	err = fast_export_ls(path, mode_out, &buf);
 	if (err) {
 		if (errno != ENOENT)
-			die_errno("BUG: unexpected fast_export_ls error");
+			BUG("unexpected fast_export_ls error: %s",
+			    strerror(errno));
 		/* Treat missing paths as directories. */
 		*mode_out = S_IFDIR;
 		return NULL;
@@ -338,7 +339,8 @@ void fast_export_copy(uint32_t revision, const char *src, const char *dst)
 	err = fast_export_ls_rev(revision, src, &mode, &data);
 	if (err) {
 		if (errno != ENOENT)
-			die_errno("BUG: unexpected fast_export_ls_rev error");
+			BUG("unexpected fast_export_ls_rev error: %s",
+			    strerror(errno));
 		fast_export_delete(dst);
 		return;
 	}
-- 
2.17.0.windows.1.36.gdf4ca5fb72a

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/4] test-tool: help verifying BUG() code paths
  2018-05-02  9:38           ` [PATCH v2 1/4] test-tool: help verifying BUG() code paths Johannes Schindelin
@ 2018-05-02 15:18             ` Duy Nguyen
  2018-05-05 19:30               ` Johannes Schindelin
  0 siblings, 1 reply; 25+ messages in thread
From: Duy Nguyen @ 2018-05-02 15:18 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Git Mailing List, Junio C Hamano, Jeff King, Johannes Sixt,
	Eric Sunshine

On Wed, May 2, 2018 at 11:38 AM, Johannes Schindelin
<johannes.schindelin@gmx.de> wrote:
> When we call BUG(), we signal via SIGABRT that something bad happened,
> dumping cores if so configured. In some setups these coredumps are
> redirected to some central place such as /proc/sys/kernel/core_pattern,
> which is a good thing.
>
> However, when we try to verify in our test suite that bugs are caught in
> certain code paths, we do *not* want to clutter such a central place
> with unnecessary coredumps.
>
> So let's special-case the test helpers (which we use to verify such code
> paths) so that the BUG() calls will *not* call abort() but exit with a
> special-purpose exit code instead.
>
> Helped-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  t/helper/test-tool.c | 2 ++
>  usage.c              | 5 +++++
>  2 files changed, 7 insertions(+)
>
> diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
> index 87066ced62a..5176f9f20ae 100644
> --- a/t/helper/test-tool.c
> +++ b/t/helper/test-tool.c
> @@ -47,7 +47,9 @@ static struct test_cmd cmds[] = {
>  int cmd_main(int argc, const char **argv)
>  {
>         int i;
> +       extern int BUG_exit_code;
>
> +       BUG_exit_code = 99;

It may be even better to let individual tests in t1406 control this,
pretty much like your original patch, except that we tell usage.c to
not send SIGABRT and just return a special fault code. That way we
don't accidentally suppress BUG()'s sigabrt behavior  in tests that do
not anticipate it (even in t1406).

But this patch is ok for me too if you don't want another reroll.

>         if (argc < 2)
>                 die("I need a test name!");
>
> diff --git a/usage.c b/usage.c
> index cdd534c9dfc..9c84dccfa97 100644
> --- a/usage.c
> +++ b/usage.c
> @@ -210,6 +210,9 @@ void warning(const char *warn, ...)
>         va_end(params);
>  }
>
> +/* Only set this, ever, from t/helper/, when verifying that bugs are caught. */
> +int BUG_exit_code;
> +
>  static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
>  {
>         char prefix[256];
> @@ -221,6 +224,8 @@ static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_lis
>                 snprintf(prefix, sizeof(prefix), "BUG: ");
>
>         vreportf(prefix, fmt, params);
> +       if (BUG_exit_code)
> +               exit(BUG_exit_code);
>         abort();
>  }
>
> --
> 2.17.0.windows.1.36.gdf4ca5fb72a
>
>



-- 
Duy

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/4] test-tool: help verifying BUG() code paths
  2018-05-02 15:18             ` Duy Nguyen
@ 2018-05-05 19:30               ` Johannes Schindelin
  0 siblings, 0 replies; 25+ messages in thread
From: Johannes Schindelin @ 2018-05-05 19:30 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: Git Mailing List, Junio C Hamano, Jeff King, Johannes Sixt,
	Eric Sunshine

[-- Attachment #1: Type: text/plain, Size: 2605 bytes --]

Hi Duy,

On Wed, 2 May 2018, Duy Nguyen wrote:

> On Wed, May 2, 2018 at 11:38 AM, Johannes Schindelin
> <johannes.schindelin@gmx.de> wrote:
> > When we call BUG(), we signal via SIGABRT that something bad happened,
> > dumping cores if so configured. In some setups these coredumps are
> > redirected to some central place such as /proc/sys/kernel/core_pattern,
> > which is a good thing.
> >
> > However, when we try to verify in our test suite that bugs are caught in
> > certain code paths, we do *not* want to clutter such a central place
> > with unnecessary coredumps.
> >
> > So let's special-case the test helpers (which we use to verify such code
> > paths) so that the BUG() calls will *not* call abort() but exit with a
> > special-purpose exit code instead.
> >
> > Helped-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  t/helper/test-tool.c | 2 ++
> >  usage.c              | 5 +++++
> >  2 files changed, 7 insertions(+)
> >
> > diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
> > index 87066ced62a..5176f9f20ae 100644
> > --- a/t/helper/test-tool.c
> > +++ b/t/helper/test-tool.c
> > @@ -47,7 +47,9 @@ static struct test_cmd cmds[] = {
> >  int cmd_main(int argc, const char **argv)
> >  {
> >         int i;
> > +       extern int BUG_exit_code;
> >
> > +       BUG_exit_code = 99;
> 
> It may be even better to let individual tests in t1406 control this,
> pretty much like your original patch, except that we tell usage.c to
> not send SIGABRT and just return a special fault code. That way we
> don't accidentally suppress BUG()'s sigabrt behavior  in tests that do
> not anticipate it (even in t1406).

I thought long and hard about this, even slept over it. And I came to the
conclusion that I do not really know whether we want such a special
treatment (you may even want to go crazier and limit *which* BUG() call
you intend to catch, so that others are still reported).

And I came to an important realization: whether or not to handle the bugs
in the way you described is actually *outside* the purpose of this patch
series. This patch series is really only about converting die(BUG:...)
calls to BUG() calls. And it simply leaves the concern you raised for
another patch series.

> But this patch is ok for me too if you don't want another reroll.

I don't ;-) (for the reasons mentioned above: I don't disagree with you, I
just think it should be addressed in another patch series than this here
patch series).

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG()
  2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
                             ` (3 preceding siblings ...)
  2018-05-02  9:38           ` [PATCH v2 4/4] Convert remaining die*(BUG) messages Johannes Schindelin
@ 2018-05-07  9:01           ` Jeff King
  4 siblings, 0 replies; 25+ messages in thread
From: Jeff King @ 2018-05-07  9:01 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: git, Junio C Hamano, Johannes Sixt,
	Nguyễn Thái Ngọc Duy, Eric Sunshine

On Wed, May 02, 2018 at 11:38:13AM +0200, Johannes Schindelin wrote:

> The BUG() macro was introduced in this patch series:
> https://public-inbox.org/git/20170513032414.mfrwabt4hovujde2@sigill.intra.peff.net
> 
> The second patch in that series converted one caller from die("BUG: ")
> to use the BUG() macro.
> 
> It seems that there was no concrete plan to address the same issue in
> the rest of the code base.

I had a plan; it was that people would convert these as they touched the
relevant areas. :)

I'm happy to see a mass-conversion, though.

> For that reason, the commit message contains the precise Unix shell
> invocation (GNU sed semantics, not BSD sed ones, because I know that the
> Git maintainer as well as the author of the patch introducing BUG() both
> use Linux and not macOS or any other platform that would offer a BSD
> sed). It should be straight-forward to handle merge
> conflicts/non-applying patches by simply re-running that command.

I suspect this could have been done with coccinelle, but it's definitely
not worth going back to re-do it now.

> Changes since v2:
> 
> - Avoided the entire discussion about the previous 2/6 (now dropped)
>   that prepared t1406 to handle SIGABRT by side-stepping the issue: the
>   ref-store test helper will no longer call abort() in BUG() calls but
>   exit with exit code 99 instead.

I actually think this should be a runtime flag in the environment, like
GIT_BUG_EXIT_CODE (and if not set, continue to abort). That can help if
you come across a BUG() in real Git code, but for some reason your
environment makes aborting a pain. For example, maybe you're debugging a
racy BUG() and don't want to generate a bunch of coredumps.

Or here's an interesting related case I came across a few months ago.
t6210 has a test that's known to segfault due to stack exhaustion. It's
marked test_expect_failure, so all is good, right?  Normally, yes, but
when I run the test suite inside our local Jenkins setup, it detects a
segfault in _any_ child process of the test runner and aborts the whole
thing. This is great as a belt-and-suspenders if we miss an unexpected
segfault, but is obviously annoying in this case.

Triggering BUG()s in the test suite, even inside an expect_failure,
would introduce the same headache. It would be nice if I could just do:

  GIT_BUG_EXIT_CODE=134 make test

to avoid it.  Possibly expect_failure should even set that
automatically.

I also suspect that nobody really needs to set a specific exit code.
Using 134 is enough to avoid all of the unpleasantness of SIGABRT, but
still enough to trigger test_must_fail to distinguish it from a non-BUG
death. The callers that intentionally trigger bugs probably ought to be
using test_expect_code to make sure they are hitting a BUG() and not
some other death, anyway.

So we could probably simplify it to something like this:

diff --git a/usage.c b/usage.c
index cdd534c9df..50651bed40 100644
--- a/usage.c
+++ b/usage.c
@@ -221,7 +221,11 @@ static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_lis
 		snprintf(prefix, sizeof(prefix), "BUG: ");
 
 	vreportf(prefix, fmt, params);
-	abort();
+
+	if (git_env_bool("GIT_BUG_ABORT"), 1)
+		abort();
+	else
+		exit(134);
 }
 
 #ifdef HAVE_VARIADIC_MACROS

-Peff

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 2/4] run-command: use BUG() to report bugs, not die()
  2018-05-02  9:38           ` [PATCH v2 2/4] run-command: use BUG() to report bugs, not die() Johannes Schindelin
@ 2018-05-07  9:08             ` Jeff King
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff King @ 2018-05-07  9:08 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: git, Junio C Hamano, Johannes Sixt,
	Nguyễn Thái Ngọc Duy, Eric Sunshine

On Wed, May 02, 2018 at 11:38:31AM +0200, Johannes Schindelin wrote:

> The slightly misleading name die_bug() of the function intended to
> report a bug is actually called always, and only reports a bug if the
> passed-in parameter `err` is non-zero.
> 
> It uses die_errno() to report the bug, to helpfully include the error
> message corresponding to `err`.
> 
> However, as these messages indicate bugs, we really should use BUG().
> And as BUG() is a macro to be able to report the exact file and line
> number, we need to convert die_bug() to a macro instead of only
> replacing the die_errno() by a call to BUG().
> 
> While at it, use a name more indicative of the purpose: CHECK_BUG().

Hrm, at first glance these _don't_ seem like BUGs, because we're
checking the value of errno. I guess the argument is that for these
_particular_ syscalls, we know that they can only complain with EINVAL,
and only when we feed them junk. And therefore any such error return is
a bug.

I guess I buy that line of reasoning for pthread_setcancelstate(). But I
think pthread_sigmask() could return an error based on in-kernel
limitations of sigsetsize. I suppose that's pretty unlikely.

But what I'm suggesting is that these probably should not have been
die("BUG") in the first place. And that the rule of thumb should
probably be that anything relying on system calls or errno should not
BUG(), but be a regular die().

-Peff

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2018-05-07  9:08 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-12 14:19 [Git 2.13.0] BUG: setup_git_env called without repository Josh Hagins
2017-05-12 14:48 ` Johannes Schindelin
2017-05-15  0:22   ` Josh Hagins
2017-05-12 20:34 ` [PATCH] config: complain about --local outside of a git repo Jeff King
2017-05-12 22:31   ` Ævar Arnfjörð Bjarmason
2017-05-13  2:03     ` Jeff King
2017-05-13  3:24       ` [PATCH 0/3] BUG() and "config --local" outside of repo Jeff King
2017-05-13  3:28         ` [PATCH 1/3] usage.c: add BUG() function Jeff King
2017-05-13  3:55           ` Jeff King
2017-05-15  2:28             ` Junio C Hamano
2017-05-13  3:29         ` [PATCH 2/3] setup_git_env: convert die("BUG") to BUG() Jeff King
2017-05-13  3:29         ` [PATCH 3/3] config: complain about --local outside of a git repo Jeff King
2018-05-02  9:38         ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Johannes Schindelin
2018-05-02  9:38           ` [PATCH v2 1/4] test-tool: help verifying BUG() code paths Johannes Schindelin
2018-05-02 15:18             ` Duy Nguyen
2018-05-05 19:30               ` Johannes Schindelin
2018-05-02  9:38           ` [PATCH v2 2/4] run-command: use BUG() to report bugs, not die() Johannes Schindelin
2018-05-07  9:08             ` Jeff King
2018-05-02  9:38           ` [PATCH v2 3/4] Replace all die("BUG: ...") calls by BUG() ones Johannes Schindelin
2018-05-02  9:38           ` [PATCH v2 4/4] Convert remaining die*(BUG) messages Johannes Schindelin
2018-05-07  9:01           ` [PATCH v2 0/4] Finish the conversion from die("BUG: ...") to BUG() Jeff King
2017-05-13  0:04   ` [PATCH] config: complain about --local outside of a git repo Jonathan Nieder
2017-05-13  2:04     ` Jeff King
2017-05-15  0:31   ` Josh Hagins
2017-05-15  3:18     ` Jeff King

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).