branch: elpa/git-commit commit 3e415b7d533cb0a8faac696a54dbe15ee0d84bea Author: Jonas Bernoulli <jo...@bernoul.li> Commit: Jonas Bernoulli <jo...@bernoul.li>
Support invoking smerge from magit buffers Closes #4458. --- Documentation/magit.org | 15 +++++++++-- Documentation/magit.texi | 15 +++++++++-- lisp/magit-apply.el | 65 ++++++++++++++++++++++++++++++++++++++++++++++-- lisp/magit-diff.el | 10 +++++++- 4 files changed, 98 insertions(+), 7 deletions(-) diff --git a/Documentation/magit.org b/Documentation/magit.org index 7e5b8e7..4c55e11 100644 --- a/Documentation/magit.org +++ b/Documentation/magit.org @@ -8,7 +8,7 @@ #+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: Magit: (magit). #+TEXINFO_DIR_DESC: Using Git from Emacs with Magit. -#+SUBTITLE: for version 3.2.1 (v3.2.1-62-g5a8e3aec3+1) +#+SUBTITLE: for version 3.2.1 (v3.2.1-64-g8771401d4+1) #+TEXINFO_DEFFN: t #+OPTIONS: H:4 num:3 toc:2 @@ -25,7 +25,7 @@ directly from within Emacs. While many fine Git clients exist, only Magit and Git itself deserve to be called porcelains. #+TEXINFO: @noindent -This manual is for Magit version 3.2.1 (v3.2.1-62-g5a8e3aec3+1). +This manual is for Magit version 3.2.1 (v3.2.1-64-g8771401d4+1). #+BEGIN_QUOTE Copyright (C) 2015-2021 Jonas Bernoulli <jo...@bernoul.li> @@ -4377,6 +4377,10 @@ variants. Remove the change at point from the working tree. + On a hunk or file with unresolved conflicts prompt which side to + keep (while discarding the other). If point is within the text + of a side, then keep that side without prompting. + - Key: v, magit-reverse Reverse the change at point in the working tree. @@ -5506,6 +5510,13 @@ to the Magit status buffer. The file should now be shown as stages the file when you save the buffer after resolving the last conflict. +Magit now wraps the mentioned Smerge commands, allowing you to use +these key bindings without having to go to the file-visiting buffer. +Additionally ~k~ (~magit-discard~) on a hunk with unresolved conflicts +asks which side to keep or, if point is on a side, then it keeps it +without prompting. Similarly ~k~ on a unresolved file ask which side +to keep. + Alternatively you could use Ediff, which uses separate buffers for the different versions of the file. To resolve conflicts in a file using Ediff press ~e~ while point is on such a file in the status buffer. diff --git a/Documentation/magit.texi b/Documentation/magit.texi index 64cd9a5..816bc3b 100644 --- a/Documentation/magit.texi +++ b/Documentation/magit.texi @@ -31,7 +31,7 @@ General Public License for more details. @finalout @titlepage @title Magit User Manual -@subtitle for version 3.2.1 (v3.2.1-62-g5a8e3aec3+1) +@subtitle for version 3.2.1 (v3.2.1-64-g8771401d4+1) @author Jonas Bernoulli @page @vskip 0pt plus 1filll @@ -53,7 +53,7 @@ directly from within Emacs. While many fine Git clients exist, only Magit and Git itself deserve to be called porcelains. @noindent -This manual is for Magit version 3.2.1 (v3.2.1-62-g5a8e3aec3+1). +This manual is for Magit version 3.2.1 (v3.2.1-64-g8771401d4+1). @quotation Copyright (C) 2015-2021 Jonas Bernoulli <jonas@@bernoul.li> @@ -5946,6 +5946,10 @@ the change to be applied to the index as well. Remove the change at point from the working tree. +On a hunk or file with unresolved conflicts prompt which side to +keep (while discarding the other). If point is within the text +of a side, then keep that side without prompting. + @kindex v @cindex magit-reverse @item @kbd{v} @tie{}@tie{}@tie{}@tie{}(@code{magit-reverse}) @@ -7377,6 +7381,13 @@ to the Magit status buffer. The file should now be shown as stages the file when you save the buffer after resolving the last conflict. +Magit now wraps the mentioned Smerge commands, allowing you to use +these key bindings without having to go to the file-visiting buffer. +Additionally @code{k} (@code{magit-discard}) on a hunk with unresolved conflicts +asks which side to keep or, if point is on a side, then it keeps it +without prompting. Similarly @code{k} on a unresolved file ask which side +to keep. + Alternatively you could use Ediff, which uses separate buffers for the different versions of the file. To resolve conflicts in a file using Ediff press @code{e} while point is on such a file in the status buffer. diff --git a/lisp/magit-apply.el b/lisp/magit-apply.el index 1feeddf..fcd7792 100644 --- a/lisp/magit-apply.el +++ b/lisp/magit-apply.el @@ -459,7 +459,11 @@ without requiring confirmation." ;;;; Discard (defun magit-discard () - "Remove the change at point." + "Remove the change at point. + +On a hunk or file with unresolved conflicts prompt which side to +keep (while discarding the other). If point is within the text +of a side, then keep that side without prompting." (interactive) (--when-let (magit-apply--get-selection) (pcase (list (magit-diff-type) (magit-diff-scope)) @@ -478,7 +482,10 @@ without requiring confirmation." (defun magit-discard-hunk (section) (magit-confirm 'discard "Discard hunk") - (magit-discard-apply section 'magit-apply-hunk)) + (let ((file (magit-section-parent-value section))) + (pcase (cddr (car (magit-file-status file))) + (`(?U ?U) (magit-smerge-keep-current)) + (_ (magit-discard-apply section 'magit-apply-hunk))))) (defun magit-discard-apply (section apply) (if (eq (magit-diff-type section) 'unstaged) @@ -735,6 +742,60 @@ a separate commit. A typical workflow would be: (interactive) (magit-reverse (cons "--cached" args))) +;;; Smerge Support + +(defun magit-smerge-keep-current () + "Keep the current version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-current)) + +(defun magit-smerge-keep-upper () + "Keep the upper/our version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-upper)) + +(defun magit-smerge-keep-base () + "Keep the base version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-base)) + +(defun magit-smerge-keep-lower () + "Keep the lower/their version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-lower)) + +(defun magit-call-smerge (fn) + (pcase-let* ((file (magit-file-at-point t t)) + (keep (get-file-buffer file)) + (`(,buf ,pos) + (let ((magit-diff-visit-jump-to-change nil)) + (magit-diff-visit-file--noselect file)))) + (with-current-buffer buf + (save-excursion + (save-restriction + (unless (<= (point-min) pos (point-max)) + (widen)) + (goto-char pos) + (condition-case nil + (smerge-match-conflict) + (error + (if (eq fn 'smerge-keep-current) + (when (eq this-command 'magit-discard) + (re-search-forward smerge-begin-re nil t) + (setq fn + (magit-read-char-case "Keep side: " t + (?o "[o]urs/upper" #'smerge-keep-upper) + (?b "[b]ase" #'smerge-keep-base) + (?t "[t]heirs/lower" #'smerge-keep-lower)))) + (re-search-forward smerge-begin-re nil t)))) + (funcall fn))) + (when (and keep (magit-anything-unmerged-p file)) + (smerge-start-session)) + (save-buffer)) + (unless keep + (kill-buffer buf)) + (magit-refresh))) + ;;; _ (provide 'magit-apply) ;;; magit-apply.el ends here diff --git a/lisp/magit-diff.el b/lisp/magit-diff.el index 88f2e5b..250a895 100644 --- a/lisp/magit-diff.el +++ b/lisp/magit-diff.el @@ -1678,11 +1678,13 @@ the Magit-Status buffer for DIRECTORY." (not (< (point) (oref section content))) (= (char-after (line-beginning-position)) ?-))) +(defvar magit-diff-visit-jump-to-change t) + (defun magit-diff-hunk-line (section goto-from) (save-excursion (goto-char (line-beginning-position)) (with-slots (content combined from-ranges from-range to-range) section - (when (< (point) content) + (when (and magit-diff-visit-jump-to-change (< (point) content)) (goto-char content) (re-search-forward "^[-+]")) (+ (car (if goto-from from-range to-range)) @@ -1976,6 +1978,12 @@ Staging and applying changes is documented in info node (defvar magit-hunk-section-map (let ((map (make-sparse-keymap))) (set-keymap-parent map magit-diff-section-base-map) + (let ((m (make-sparse-keymap))) + (define-key m (kbd "RET") 'magit-smerge-keep-current) + (define-key m (kbd "u") 'magit-smerge-keep-upper) + (define-key m (kbd "b") 'magit-smerge-keep-base) + (define-key m (kbd "l") 'magit-smerge-keep-lower) + (define-key map smerge-command-prefix m)) map) "Keymap for `hunk' sections.")