]> git.eshelyaron.com Git - emacs.git/commitdiff
; * admin/cherry.el: New file.
authorEshel Yaron <me@eshelyaron.com>
Fri, 22 Dec 2023 18:08:49 +0000 (19:08 +0100)
committerEshel Yaron <me@eshelyaron.com>
Fri, 22 Dec 2023 18:09:09 +0000 (19:09 +0100)
Add helper command 'cherry-pick-new-commits' for interactively
cherry-picking new commits from the upstream master branch.

admin/cherry-skip-list [new file with mode: 0644]
admin/cherry.el [new file with mode: 0644]

diff --git a/admin/cherry-skip-list b/admin/cherry-skip-list
new file mode 100644 (file)
index 0000000..912d230
--- /dev/null
@@ -0,0 +1,17 @@
+5f923ff1a6a8a9ff6f06dc49c8e0e2ceee111567
+945aa0e42bc08879a9c979cbffb9b3f50e4945f3
+8e52a59808e9ca1b8e535725eb76b83e409745eb
+22b2390c66e2f9a5f3bcb2f1727c830348a6e61d
+7a7491a23eacaae41c07568d833e668ec1d351cf
+598ab9ca10d35d6990f9af3a4d58f265acd8b121
+8e0882d17a38cb9d309df705e76a8e88529f30a9
+46367e0a5c9a58087d59f19966b23ee980bdbb24
+67e16d37e9c83fea9f67d144eeac27a83d52c949
+73acd543cb1f88af880445de1e1a7238dd46c9de
+b499d4f65a7c1ce45500dcbf1c5c63d85241b330
+2e5d50ee43096ff5422c88f835ccceb1728def06
+3aa9fbf4fab2f21c0a6f0dba510bfe8266578f2f
+7058988fd65d719b69b658a74b268d4a2f1909c5
+4239c27f3867b558ae2e26950d5153d496b02d8f
+91f2ade57bb72e9bb4a44da44e5dc69adb3c7584
+93592c69179a8d5ccf1f09c3f26e91f194772b8e
diff --git a/admin/cherry.el b/admin/cherry.el
new file mode 100644 (file)
index 0000000..ffcdcd7
--- /dev/null
@@ -0,0 +1,112 @@
+;;; cherry.el --- Cherry pick commits from upstream master  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library defines the command `cherry-pick-new-commits' that
+;; iterates over new commits in the upstream master branch, and
+;; suggests cherry-picking them one after the other.
+
+;;; Code:
+
+(defvar cherry-upstream-remote "upstream")
+
+(defvar cherry-upstream-branch "master")
+
+(defvar cherry-skip-list-file
+  (expand-file-name "admin/cherry-skip-list" source-directory))
+
+(defun cherry-merge-base ()
+  (car
+   (string-lines
+    (shell-command-to-string
+     (concat "git -C " source-directory " merge-base "
+             cherry-upstream-remote "/" cherry-upstream-branch
+             " HEAD"))
+    t)))
+
+(defun cherry-picked-p (commit merge-base)
+  (car
+   (string-lines
+    (shell-command-to-string
+     (concat "git log -1 --pretty=%H --grep='(cherry picked from commit "
+             commit
+             ")' "
+             merge-base "..HEAD"))
+    t)))
+
+(defun cherry-skipped-p (commit)
+  (= 0 (call-process "grep" cherry-skip-list-file nil nil
+                     "-q" "-E" (concat "^" commit))))
+
+(defun cherry-upstream-commits ()
+  (string-lines
+   (shell-command-to-string
+    (concat "git -C " source-directory " cherry HEAD upstream/master | grep -vE '^-' | cut -f 2 -d ' '"))
+   t))
+
+(defun cherry-pick-new-commits ()
+  "Pick or skip new commits in the upstream branch."
+  (interactive)
+  (call-process "git" nil nil nil
+                "-C" source-directory "fetch" cherry-upstream-remote)
+  (let* ((merge-base (cherry-merge-base))
+         (new-commits
+          (seq-remove
+           (lambda (commit)
+             (or (cherry-picked-p commit merge-base)
+                 (cherry-skipped-p commit)))
+           (cherry-upstream-commits))))
+    (if new-commits
+        (dolist (commit new-commits)
+          (with-current-buffer (get-buffer-create "*cherry*")
+            (delete-region (point-min) (point-max))
+            (fundamental-mode))
+          (call-process "git" nil "*cherry*" t "-C" source-directory
+                        "format-patch" "-1" commit "--stdout")
+          (pop-to-buffer "*cherry*")
+          (diff-mode)
+          (goto-char (point-min))
+          (let ((choice (read-multiple-choice
+                         "Pick?"
+                         '((?p "pick")
+                           (?s "skip")
+                           (?q "quit")
+                           ;; (?a "amend")
+                           ))))
+            (pcase (car choice)
+              (?s
+               (message "Skipping...")
+               (shell-command (concat "echo " commit
+                                      (read-string "Reason: " "")
+                                      ">>" cherry-skip-list-file))
+               (message "Skipped."))
+              (?p
+               (message "Picking...")
+               (if (= 0 (call-process "git" nil nil nil
+                                      "-C" source-directory
+                                      "cherry-pick" "-x" commit))
+                   (message "Picked.")
+                 (user-error "Cherry picking failed")))
+              (?q (bury-buffer "*cherry*")
+                  (user-error "Quit cherry picking")))))
+      (message "No new commits."))))
+
+(provide 'cherry)
+;;; cherry.el ends here