I've been using Git worktrees for quite a while during agentic coding, and it's been largely successful with my current workflow. One hassle to perform inside of Emacs after some changes in worktrees is that I have to go to the worktrees and rebase them to the main branch one by one. In Magit, this is relatively easy when performed individually. But when I have more than one worktrees need rebasing, it quickly become a repetitive chore.

Since Emacs is highly extensible, I wonder if I can inject a transient command such that each time I want to rebase the worktrees, it's just one command away for all worktrees.

Here it is.

  ;;;; Inside of user-lisp/ folder
  (defcustom my-magit-worktree-base-branch "main"
    "Branch onto which `my-magit-rebase-all-worktrees' rebases worktrees."
    :type 'string
    :group 'magit-commands)

  ;;;###autoload
  (defun my-magit-rebase-all-worktrees ()
    "Rebase every clean worktree onto `my-magit-worktree-base-branch'.

  The base branch itself and detached, bare, missing, or dirty worktrees are
  skipped.  Stop at the first failed rebase so that at most one worktree is
  left needing conflict resolution."
    (interactive)
    (let* ((default-directory (file-name-as-directory (magit-toplevel)))
           (base my-magit-worktree-base-branch)
           (worktrees (magit-list-worktrees))
           (log-buffer (get-buffer-create "*Magit update worktrees*"))
           updated skipped failed)
      (unless (magit-local-branch-p base)
        (user-error "No local branch named %s" base))
      (with-current-buffer log-buffer
        (let ((inhibit-read-only t))
          (fundamental-mode)
          (setq buffer-read-only nil)
          (erase-buffer)
          (insert (format "Rebasing worktrees onto %s\n\n" base))))
      (catch 'rebase-failed
        (pcase-dolist (`(,directory ,_commit ,branch ,bare ,detached
                                    ,_locked ,prunable)
                       worktrees)
          (let ((reason
                 (cond
                  ((equal branch base) "base branch")
                  (bare "bare")
                  (detached "detached HEAD")
                  ((or prunable (not (file-directory-p directory))) "missing")
                  ((let ((default-directory
                          (file-name-as-directory directory)))
                     (magit-git-lines "status" "--porcelain"))
                   "dirty"))))
            (if reason
                (push (format "%s (%s)" (or branch directory) reason) skipped)
              (with-current-buffer log-buffer
                (let ((inhibit-read-only t))
                  (goto-char (point-max))
                  (insert (format "$ git -C %s rebase %s\n"
                                  (shell-quote-argument directory)
                                  (shell-quote-argument base)))))
              (let* ((default-directory (file-name-as-directory directory))
                     (process-environment
                      (cons "GIT_EDITOR=:" process-environment))
                     (exit-code
                      (process-file "git" nil (list log-buffer t) nil
                                    "rebase" base)))
                (with-current-buffer log-buffer
                  (let ((inhibit-read-only t))
                    (goto-char (point-max))
                    (insert "\n")))
                (if (and (integerp exit-code) (zerop exit-code))
                    (push branch updated)
                  (setq failed (cons branch directory))
                  (throw 'rebase-failed nil)))))))
      (with-current-buffer log-buffer
        (special-mode))
      (magit-refresh-all)
      (if failed
          (progn
            (display-buffer log-buffer)
            (user-error "Rebase failed in %s (%s); resolve or abort it there"
                        (car failed) (cdr failed)))
        (message "Rebased %d worktree%s onto %s%s"
                 (length updated)
                 (if (= (length updated) 1) "" "s")
                 base
                 (if skipped
                     (format "; skipped %s" (string-join (nreverse skipped) ", "))
                   "")))))

  ;;;; In init.el
  (use-package magit
    :functions magit-insert-worktrees
    :bind ("C-x g" . magit-status)
    :config
    (add-hook 'magit-status-sections-hook #'magit-insert-worktrees t)
    (transient-append-suffix 'magit-worktree "g"
      '("u" "Update all from main" my-magit-rebase-all-worktrees)))

It's inserting into magit-worktree, so you can invoke it with Z u inside of Magit.