diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb
index b9306e7ee4..776d9f06f2 100644
--- a/Library/Homebrew/brew.rb
+++ b/Library/Homebrew/brew.rb
@@ -93,6 +93,15 @@ begin
internal_cmd ||= begin
internal_dev_cmd = Commands.valid_internal_dev_cmd?(cmd)
if internal_dev_cmd && !Homebrew::EnvConfig.developer?
+ if ENV["HOMEBREW_DEV_CMD_RUN"].blank?
+ opoo <<~MESSAGE
+ #{Tty.bold}#{cmd}#{Tty.reset} is a developer command, so
+ Homebrew's developer mode has been automatically turned on.
+ To turn developer mode off, run #{Tty.bold}brew developer off#{Tty.reset}
+
+ MESSAGE
+ end
+
Homebrew::Settings.write "devcmdrun", true
ENV["HOMEBREW_DEV_CMD_RUN"] = "1"
end
diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh
index cb69767ebb..312a029742 100644
--- a/Library/Homebrew/brew.sh
+++ b/Library/Homebrew/brew.sh
@@ -81,6 +81,30 @@ ohai() {
fi
}
+opoo() {
+ if [[ -n "${HOMEBREW_COLOR}" || (-t 2 && -z "${HOMEBREW_NO_COLOR}") ]] # check whether stderr is a tty.
+ then
+ echo -ne "\\033[4;33mWarning\\033[0m: " >&2 # highlight Warning with underline and yellow color
+ else
+ echo -n "Warning: " >&2
+ fi
+ if [[ $# -eq 0 ]]
+ then
+ cat >&2
+ else
+ echo "$*" >&2
+ fi
+}
+
+bold() {
+ if [[ -n "${HOMEBREW_COLOR}" || (-t 2 && -z "${HOMEBREW_NO_COLOR}") ]] # check whether stderr is a tty.
+ then
+ echo -e "\\033[1m""$*""\\033[0m"
+ else
+ echo "$*"
+ fi
+}
+
onoe() {
if [[ -n "${HOMEBREW_COLOR}" || (-t 2 && -z "${HOMEBREW_NO_COLOR}") ]] # check whether stderr is a tty.
then
@@ -621,6 +645,15 @@ elif [[ -f "${HOMEBREW_LIBRARY}/Homebrew/dev-cmd/${HOMEBREW_COMMAND}.sh" ]]
then
if [[ -z "${HOMEBREW_DEVELOPER}" ]]
then
+ if [[ -z "${HOMEBREW_DEV_CMD_RUN}" ]]
+ then
+ message="$(bold "${HOMEBREW_COMMAND}") is a developer command, so
+Homebrew's developer mode has been automatically turned on.
+To turn developer mode off, run $(bold "brew developer off")
+"
+ opoo "${message}"
+ fi
+
git config --file="${HOMEBREW_GIT_CONFIG_FILE}" --replace-all homebrew.devcmdrun true 2>/dev/null
export HOMEBREW_DEV_CMD_RUN="1"
fi
diff --git a/Library/Homebrew/cmd/developer.rb b/Library/Homebrew/cmd/developer.rb
new file mode 100755
index 0000000000..e967844b7a
--- /dev/null
+++ b/Library/Homebrew/cmd/developer.rb
@@ -0,0 +1,58 @@
+# typed: true
+# frozen_string_literal: true
+
+require "cli/parser"
+
+module Homebrew
+ extend T::Sig
+
+ module_function
+
+ sig { returns(CLI::Parser) }
+ def developer_args
+ Homebrew::CLI::Parser.new do
+ description <<~EOS
+ Control Homebrew's developer mode. When developer mode is enabled,
+ `brew update` will update Homebrew to the latest commit on the `master`
+ branch instead of the latest stable version along with some other behaviour changes.
+
+ `brew developer` [`state`]:
+ Display the current state of Homebrew's developer mode.
+
+ `brew developer` (`on`|`off`):
+ Turn Homebrew's developer mode on or off respectively.
+ EOS
+
+ named_args %w[state on off], max: 1
+ end
+ end
+
+ def developer
+ args = developer_args.parse
+
+ env_vars = []
+ env_vars << "HOMEBREW_DEVELOPER" if Homebrew::EnvConfig.developer?
+ env_vars << "HOMEBREW_UPDATE_TO_TAG" if Homebrew::EnvConfig.update_to_tag?
+ env_vars.map! do |var|
+ "#{Tty.bold}#{var}#{Tty.reset}"
+ end
+
+ case args.named.first
+ when nil, "state"
+ if env_vars.any?
+ puts "Developer mode is enabled because #{env_vars.to_sentence} #{"is".pluralize(env_vars.count)} set."
+ elsif Homebrew::Settings.read("devcmdrun") == "true"
+ puts "Developer mode is enabled."
+ else
+ puts "Developer mode is disabled."
+ end
+ when "on"
+ Homebrew::Settings.write "devcmdrun", true
+ when "off"
+ Homebrew::Settings.delete "devcmdrun"
+ puts "To fully disable developer mode, you must unset #{env_vars.to_sentence}." if env_vars.any?
+ else
+ raise UsageError, "unknown subcommand: #{args.named.first}"
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cmd/developer_spec.rb b/Library/Homebrew/test/cmd/developer_spec.rb
new file mode 100644
index 0000000000..00ca2f5739
--- /dev/null
+++ b/Library/Homebrew/test/cmd/developer_spec.rb
@@ -0,0 +1,8 @@
+# typed: false
+# frozen_string_literal: true
+
+require "cmd/shared_examples/args_parse"
+
+describe "brew developer" do
+ it_behaves_like "parseable arguments"
+end
diff --git a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb
index 9ef36a0175..c5239ebd20 100644
--- a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb
+++ b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb
@@ -83,6 +83,7 @@ RSpec.shared_context "integration test" do # rubocop:disable RSpec/ContextWordin
"HOMEBREW_INTEGRATION_TEST" => command_id_from_args(args),
"HOMEBREW_TEST_TMPDIR" => TEST_TMPDIR,
"HOMEBREW_DEVELOPER" => ENV["HOMEBREW_DEVELOPER"],
+ "HOMEBREW_DEV_CMD_RUN" => "true",
"GEM_HOME" => nil,
)
diff --git a/completions/bash/brew b/completions/bash/brew
index 17a282cd4f..c24e439f49 100644
--- a/completions/bash/brew
+++ b/completions/bash/brew
@@ -746,6 +746,23 @@ _brew_desc() {
__brew_complete_formulae
}
+_brew_developer() {
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ case "${cur}" in
+ -*)
+ __brewcomp "
+ --debug
+ --help
+ --quiet
+ --verbose
+ "
+ return
+ ;;
+ *)
+ esac
+ __brewcomp "state on off"
+}
+
_brew_dispatch_build_bottle() {
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${cur}" in
@@ -2446,6 +2463,7 @@ _brew() {
create) _brew_create ;;
deps) _brew_deps ;;
desc) _brew_desc ;;
+ developer) _brew_developer ;;
dispatch-build-bottle) _brew_dispatch_build_bottle ;;
doctor) _brew_doctor ;;
dr) _brew_dr ;;
diff --git a/completions/fish/brew.fish b/completions/fish/brew.fish
index 78245fa06b..836b32f0d3 100644
--- a/completions/fish/brew.fish
+++ b/completions/fish/brew.fish
@@ -578,6 +578,16 @@ __fish_brew_complete_arg 'desc' -l verbose -d 'Make some output more verbose'
__fish_brew_complete_arg 'desc' -a '(__fish_brew_suggest_formulae_all)'
+__fish_brew_complete_cmd 'developer' 'Control Homebrew\'s developer mode'
+__fish_brew_complete_sub_cmd 'developer' 'state'
+__fish_brew_complete_sub_cmd 'developer' 'on'
+__fish_brew_complete_sub_cmd 'developer' 'off'
+__fish_brew_complete_arg 'developer' -l debug -d 'Display any debugging information'
+__fish_brew_complete_arg 'developer' -l help -d 'Show this message'
+__fish_brew_complete_arg 'developer' -l quiet -d 'Make some output more quiet'
+__fish_brew_complete_arg 'developer' -l verbose -d 'Make some output more verbose'
+
+
__fish_brew_complete_cmd 'dispatch-build-bottle' 'Build bottles for these formulae with GitHub Actions'
__fish_brew_complete_arg 'dispatch-build-bottle' -l debug -d 'Display any debugging information'
__fish_brew_complete_arg 'dispatch-build-bottle' -l help -d 'Show this message'
diff --git a/completions/internal_commands_list.txt b/completions/internal_commands_list.txt
index 80641b01ea..e5ac7b212c 100644
--- a/completions/internal_commands_list.txt
+++ b/completions/internal_commands_list.txt
@@ -29,6 +29,7 @@ config
create
deps
desc
+developer
dispatch-build-bottle
doctor
dr
diff --git a/completions/zsh/_brew b/completions/zsh/_brew
index bdceb6fd42..bbb638651f 100644
--- a/completions/zsh/_brew
+++ b/completions/zsh/_brew
@@ -155,6 +155,7 @@ __brew_internal_commands() {
'create:Generate a formula or, with `--cask`, a cask for the downloadable file at URL and open it in the editor'
'deps:Show dependencies for formula'
'desc:Display formula'\''s name and one-line description'
+ 'developer:Control Homebrew'\''s developer mode'
'dispatch-build-bottle:Build bottles for these formulae with GitHub Actions'
'doctor:Check your system for potential problems'
'edit:Open a formula or cask in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the Homebrew repository for editing if no formula is provided'
@@ -710,6 +711,17 @@ _brew_desc() {
'*::formula:__brew_formulae'
}
+# brew developer
+_brew_developer() {
+ _arguments \
+ '--debug[Display any debugging information]' \
+ '--help[Show this message]' \
+ '--quiet[Make some output more quiet]' \
+ '--verbose[Make some output more verbose]' \
+ - subcommand \
+ '*::subcommand:(state on off)'
+}
+
# brew dispatch-build-bottle
_brew_dispatch_build_bottle() {
_arguments \
diff --git a/docs/Manpage.md b/docs/Manpage.md
index 986b1135eb..6469b68ac6 100644
--- a/docs/Manpage.md
+++ b/docs/Manpage.md
@@ -184,6 +184,18 @@ first search, making that search slower than subsequent ones.
* `-d`, `--description`:
Search just descriptions for *`text`*. If *`text`* is flanked by slashes, it is interpreted as a regular expression.
+### `developer` [*`subcommand`*]
+
+Control Homebrew's developer mode. When developer mode is enabled,
+`brew update` will update Homebrew to the latest commit on the `master`
+branch instead of the latest stable version along with some other behaviour changes.
+
+`brew developer` [`state`]
+
Display the current state of Homebrew's developer mode.
+
+`brew developer` (`on`|`off`)
+
Turn Homebrew's developer mode on or off respectively.
+
### `doctor`, `dr` [*`--list-checks`*] [*`--audit-debug`*] [*`diagnostic_check`* ...]
Check your system for potential problems. Will exit with a non-zero status
diff --git a/manpages/brew.1 b/manpages/brew.1
index c23ea2a247..555f9755b3 100644
--- a/manpages/brew.1
+++ b/manpages/brew.1
@@ -229,6 +229,17 @@ Search just names for \fItext\fR\. If \fItext\fR is flanked by slashes, it is in
\fB\-d\fR, \fB\-\-description\fR
Search just descriptions for \fItext\fR\. If \fItext\fR is flanked by slashes, it is interpreted as a regular expression\.
.
+.SS "\fBdeveloper\fR [\fIsubcommand\fR]"
+Control Homebrew\'s developer mode\. When developer mode is enabled, \fBbrew update\fR will update Homebrew to the latest commit on the \fBmaster\fR branch instead of the latest stable version along with some other behaviour changes\.
+.
+.P
+\fBbrew developer\fR [\fBstate\fR]
+ Display the current state of Homebrew\'s developer mode\.
+.
+.P
+\fBbrew developer\fR (\fBon\fR|\fBoff\fR)
+ Turn Homebrew\'s developer mode on or off respectively\.
+.
.SS "\fBdoctor\fR, \fBdr\fR [\fI\-\-list\-checks\fR] [\fI\-\-audit\-debug\fR] [\fIdiagnostic_check\fR \.\.\.]"
Check your system for potential problems\. Will exit with a non\-zero status if any potential problems are found\. Please note that these warnings are just used to help the Homebrew maintainers with debugging if you file an issue\. If everything you use Homebrew for is working fine: please don\'t worry or file an issue; just ignore this\.
.