(defvar cherry-skip-list-file
(expand-file-name "admin/cherry-skip-list" source-directory))
+(defun cherry--call-git (&rest args)
+ (apply #'call-process "git" nil nil nil "-C" source-directory args))
+
(defun cherry-merge-base ()
(car
(string-lines
(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 ' '"))
+ (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)
+ (message "Ensuring working directory is clean...")
+ (or (eq 0 (cherry--call-git "diff-index" "--quiet" "HEAD" "--"))
+ (user-error "Working directory is dirty, cannot start cherry picking"))
(message "Fetching from upstream...")
- (call-process "git" nil nil nil
- "-C" source-directory "fetch" cherry-upstream-remote)
+ (cherry--call-git "fetch" cherry-upstream-remote)
(message "Checking for new commits...")
(let* ((merge-base (cherry-merge-base))
(new-commits
(cherry-upstream-commits))))
(if (null new-commits)
(message "No 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")))))
+ (let ((num-new (length new-commits))
+ (current 0))
+ (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
+ (format "[%d/%d] Pick?"
+ (setq current (1+ current))
+ num-new)
+ '((?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))
+ (cherry--call-git "commit" "-m"
+ (concat "; Skip commit " commit)
+ (file-relative-name
+ cherry-skip-list-file source-directory))
+ (message "Added to skip list and committed."))
+ (?p
+ (message "Picking...")
+ (if (= 0 (cherry--call-git "cherry-pick" "-x" commit))
+ (message "Picked.")
+ (user-error "Cherry picking failed")))
+ (?q (bury-buffer "*cherry*")
+ (user-error "Quit cherry picking"))))))
(message "Done."))))
(provide 'cherry)