Is there a simple way to add parent node in org-mode?

* heading
... # 100 or more first-level headings over here
* heading # interspersed with ones with subtrees
** heading
** heading
*** heading

I would like to add a NEW HEADING to the above so that everything else shifts down and right.

** heading
*** heading
*** heading
**** heading

Currently, selecting everything and hitting M-→ works just some of the time. It gets cumbersome when many sub and/or sub-sub headings are involved.


I presently use mark set to select region to be demoted. It works only in a specific way and not all the time. Namely, I need to:

  1. C-@ ↓ somewhere above the first * heading
  2. Move the cursor to the left-most * just below the region the be selected
  3. Hit M-→

Any other method would fail incessantly.

  • "Is there a way to..." is not about debugging - that tag is inappropriate here.
    – Drew
    Commented Jun 18, 2019 at 14:20

3 Answers 3


This function inserts a new parent/root node above the current subtree and demotes the original subtree respectively:

(defun org-insert-parent-node ()
  (catch 'exit
    (while (or (org-up-heading-safe)
               (= (org-outline-level) 1))
      (when (= (org-outline-level) 1)
          (throw 'exit t))))))

Edit: I reread your question and I think you also want to include first-level headings above the current subtree. With this command you can select the current subtree and any number of first-level headings above it:

(defun org-insert-parent-node (beg end)
  (interactive (list (region-beginning) (region-end)))
    (narrow-to-region beg end)
    (let ((beg (save-excursion
                 (goto-char beg)
                 (skip-chars-forward "* ")
           (end (save-excursion
                  (goto-char end)
       (goto-char beg)
       (goto-char beg)
         (while (outline-next-heading)
           (unless (= end (point))

org-demote-subtree does that. It is bound to C-c C->.

  • C-c C-> works only when there are hidden subtrees under a heading. It is still cumbersome when I have, say 100 first-level headings which I would like to demote in bulk so that they can be bound to a single parent.
    – Sati
    Commented Jun 18, 2019 at 10:17
  • @Sati How should Orgmode know without region which first-level headings you want to demote?
    – Tobias
    Commented Jun 18, 2019 at 10:20
  • I presently use mark set (selecting the headings to be demoted) to tell. Works only in small regions. And not all the time. Could this be a bug?
    – Sati
    Commented Jun 18, 2019 at 10:21
  • A workaround would be to use regex find and replace. But it does get complicated when subtrees are involved.
    – Sati
    Commented Jun 18, 2019 at 10:26
  • 1
    @Sati You must apply org-metaright carefully. Point may not be at a table, a drawer, or a block and either point or mark must be at a heading. (See the function definition for org-metaright.
    – Tobias
    Commented Jun 18, 2019 at 10:31

As you might know, org-mode files are plaintext-based and heading depth is determined by the number of * characters in front of it

This means you can simply insert a * in front of all headings you want to be demoted in plaintext instead of relying on org-mode functions. You don't even need to exit org-mode for that.

The easiest way to do this I know of is to enter rectangle-mark-mode (C-x SPC) at the beginning of the first line, navigate to the beginning of the last line and use string-insert-rectangle (C-t) to enter as many * as levels you want to demote the headings by.
(Evil-mode users can use C-v and I instead.)

EDIT: This only works if there is no text under headings

The slightly more complicated way that also works with text under heading is to mark the lines you want to demote and use replace-regexp to replace ^* with ** and ^SPC with SPCSPC.
(Evil-mode user can use C-V to mark and :'<,'>s/^*/**/g to replace)

  • Would this work if there are text under the headings? Wouldn't I be entering the * in the middle of the text as well?
    – Sati
    Commented Jan 7, 2020 at 0:56
  • That's true, I didn't have any in my test data, so I didn't notice. You should be able to do a regex search and replace instead though, I'll update my answer.
    – Atemu
    Commented Jan 8, 2020 at 0:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.