diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb
index a1d5363273a6108258d42a7d7c921d1c2cb4dd05..16e46f2784e60559a5edd719cc573aad83916cba 100644
--- a/Library/Homebrew/dev-cmd/tap-new.rb
+++ b/Library/Homebrew/dev-cmd/tap-new.rb
@@ -9,11 +9,15 @@ module Homebrew
   def tap_new_args
     Homebrew::CLI::Parser.new do
       usage_banner <<~EOS
-        `tap-new` <user>`/`<repo>
+        `tap-new` [<options>] <user>`/`<repo>
 
         Generate the template files for a new tap.
       EOS
 
+      switch "--no-git",
+             description: "Don't initialize a git repository for the tap."
+      flag   "--pull-label",
+             description: "Label name for pull requests ready to be pulled (default `pr-pull`)."
       named 1
     end
   end
@@ -21,8 +25,10 @@ module Homebrew
   def tap_new
     args = tap_new_args.parse
 
+    label = args.pull_label || "pr-pull"
+
     tap_name = args.named.first
-    tap = Tap.fetch(args.named.first)
+    tap = Tap.fetch(tap_name)
     raise "Invalid tap name '#{tap_name}'" unless tap.path.to_s.match?(HOMEBREW_TAP_PATH_REGEX)
 
     titleized_user = tap.user.dup
@@ -45,7 +51,7 @@ module Homebrew
     MARKDOWN
     write_path(tap, "README.md", readme)
 
-    actions = <<~YAML
+    actions_main = <<~YAML
       name: brew test-bot
       on:
         push:
@@ -53,10 +59,10 @@ module Homebrew
         pull_request:
       jobs:
         test-bot:
-          runs-on: ${{ matrix.os }}
           strategy:
             matrix:
               os: [ubuntu-latest, macOS-latest]
+          runs-on: ${{ matrix.os }}
           steps:
             - name: Set up Homebrew
               id: set-up-homebrew
@@ -82,12 +88,70 @@ module Homebrew
 
             - run: brew test-bot --only-formulae
               if: github.event_name == 'pull_request'
+
+            - name: Upload bottles as artifact
+              if: always() && github.event_name == 'pull_request'
+              uses: actions/upload-artifact@main
+              with:
+                name: bottles
+                path: '*.bottle.*'
+    YAML
+
+    actions_publish = <<~YAML
+      name: brew pr-pull
+      on:
+        pull_request_target:
+          types:
+            - labeled
+      jobs:
+        pr-pull:
+          if: contains(github.event.pull_request.labels.*.name, #{label})
+          runs-on: ubuntu-latest
+          steps:
+            - name: Set up Homebrew
+              uses: Homebrew/actions/setup-homebrew@master
+
+            - name: Set up git
+              uses: Homebrew/actions/git-user-config@master
+
+            - name: Pull bottles
+              env:
+                HOMEBREW_GITHUB_API_TOKEN: ${{ github.token }}
+                PULL_REQUEST: ${{ github.event.pull_request.number }}
+              run: brew pr-pull --debug --tap=$GITHUB_REPOSITORY $PULL_REQUEST
+
+            - name: Push commits
+              uses: Homebrew/actions/git-try-push@master
+              with:
+                token: ${{ github.token }}
+
+            - name: Delete branch
+              if: github.event.pull_request.head.repo.fork == false
+              env:
+                BRANCH: ${{ github.event.pull_request.head.ref }}
+              run: git push --delete origin $BRANCH
     YAML
 
     (tap.path/".github/workflows").mkpath
-    write_path(tap, ".github/workflows/tests.yml", actions)
+    write_path(tap, ".github/workflows/tests.yml", actions_main)
+    write_path(tap, ".github/workflows/publish.yml", actions_publish)
+
+    unless args.no_git?
+      cd tap.path do
+        safe_system "git", "init"
+        safe_system "git", "add", "--all"
+        safe_system "git", "commit", "-m", "Create #{tap} tap"
+      end
+    end
+
     ohai "Created #{tap}"
-    puts tap.path.to_s
+    puts <<~EOS
+      #{tap.path}
+
+      When a pull request making changes to a formula (or formulae) becomes green
+      (all checks passed), then you can publish the built bottles.
+      To do so, label your PR as `#{label}` and the workflow will be triggered.
+    EOS
   end
 
   def write_path(tap, filename, content)
diff --git a/docs/Manpage.md b/docs/Manpage.md
index 88ec6e5faa19e3ccd23e81a7013c534225995102..52734bf8e3bc601cd8a710b55e78379be9f9aee1 100644
--- a/docs/Manpage.md
+++ b/docs/Manpage.md
@@ -1240,10 +1240,15 @@ including core code and all formulae.
 * `--except-cops`:
   Specify a comma-separated *`cops`* list to skip checking for violations of the listed RuboCop cops.
 
-### `tap-new` *`user`*`/`*`repo`*
+### `tap-new` [*`options`*] *`user`*`/`*`repo`*
 
 Generate the template files for a new tap.
 
+* `--no-git`:
+  Don't initialize a git repository for the tap.
+* `--pull-label`:
+  Label name for pull requests ready to be pulled (default `pr-pull`).
+
 ### `test` [*`options`*] *`formula`*
 
 Run the test method provided by an installed formula.
diff --git a/manpages/brew.1 b/manpages/brew.1
index 6203447fd5dbc7370c0b778cec67ed3616c3630a..9e24e37f2fde7d1e69325697f7a0517df5285831 100644
--- a/manpages/brew.1
+++ b/manpages/brew.1
@@ -1738,9 +1738,17 @@ Specify a comma\-separated \fIcops\fR list to check for violations of only the l
 \fB\-\-except\-cops\fR
 Specify a comma\-separated \fIcops\fR list to skip checking for violations of the listed RuboCop cops\.
 .
-.SS "\fBtap\-new\fR \fIuser\fR\fB/\fR\fIrepo\fR"
+.SS "\fBtap\-new\fR [\fIoptions\fR] \fIuser\fR\fB/\fR\fIrepo\fR"
 Generate the template files for a new tap\.
 .
+.TP
+\fB\-\-no\-git\fR
+Don\'t initialize a git repository for the tap\.
+.
+.TP
+\fB\-\-pull\-label\fR
+Label name for pull requests ready to be pulled (default \fBpr\-pull\fR)\.
+.
 .SS "\fBtest\fR [\fIoptions\fR] \fIformula\fR"
 Run the test method provided by an installed formula\. There is no standard output or return code, but generally it should notify the user if something is wrong with the installed formula\.
 .