2

Suppose we have:

* Parent
** Child1 :@Tag:
*** Child of Child1
** Child2
*** Child of Child2
** Child3 :@Tag:
*** Child of Child3

Is there a way to copy all subtrees of * Parent with tag @Tag to a destination (say * Destination), so that we get:

* Destination
** Child1 :@Tag:
*** Child of Child1
** Child3 :@Tag:
*** Child of Child3
2

Sadly `org-refile' isn't a programmatically friendly function. What you want to do is generate a RFLOC parameter value for your desired target and use "Copy" as the MSG value. Here's some code to do it programmatically.

I recommend using org ID's whenever possible to virtually eliminate any ambiguity in reference to headings. First, create an ID for the destination and use that.

(let* ((target-heading "Destination")
       (target-marker (org-find-exact-headline-in-buffer target-heading))
       (target-id (save-excursion (goto-char target-marker)
                                  (org-id-get-create))))
  target-id)
;; => "22bdee5f-3c93-4ca7-b944-48db2ddc3538"

Then here is a function to help programmatically refile or copy those headings:

(defun ebpa/refile-matches-to-heading (match target-heading-id &optional scope copy)
  "Refile all headings within SCOPE (per `org-map-entries') to TARGET-HEADING-ID."
  (if-let (target-marker (org-id-find target-heading-id t))
      (let* ((target-rfloc (with-current-buffer (marker-buffer target-marker)
                             (goto-char target-marker)
                             (list (org-get-heading)
                                   (buffer-file-name (marker-buffer target-marker))
                                   nil
                                   target-marker)))
             (headings-to-copy (org-map-entries (lambda () (point-marker)) match scope)))
        (mapc
         (lambda (heading-marker)
           (with-current-buffer (marker-buffer heading-marker)
             (goto-char heading-marker)
             (org-refile nil nil target-rfloc (when copy "Copy"))))
         headings-to-copy)
        (message "%s %d headings!"
                 (if copy "Copied" "Refiled")
                 (length headings-to-copy)))
    (warn "Could not find target heading %S" target-heading-id)))

You can use it in the following way:

(ebpa/refile-matches-to-heading
 "TAGS={@Tag}"
 "22bdee5f-3c93-4ca7-b944-48db2ddc3538"
 'file
 t)
| improve this answer | |
  • This works, but it has a weird effect of joining header lines together (from the original org header that you're trying to partially refile) after running. I skimmed your code and don't see anything that could affect the layout of the original org-headers though. Any ideas of what's causing this? – George Oct 23 '17 at 13:17
  • 1
    @George Sorry about that. The bug in my code is early use of marker-position. I'll fix it shortly. (Fixed) I don't know why I thought org-refile would accept a position, but not a marker. – ebpa Oct 23 '17 at 16:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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