update packages

This commit is contained in:
2025-06-22 17:08:08 +02:00
parent 54e5633369
commit 16a0a6db93
558 changed files with 68349 additions and 26568 deletions

15
lisp/magit/.dir-locals.el Normal file
View File

@@ -0,0 +1,15 @@
((nil
(indent-tabs-mode . nil))
(makefile-mode
(indent-tabs-mode . t)
(outline-regexp . "#\\(#+\\)")
(mode . outline-minor))
(emacs-lisp-mode
(checkdoc-allow-quoting-nil-and-t . t))
(git-commit-mode
(git-commit-major-mode . git-commit-elisp-text-mode))
(".github/PULL_REQUEST_TEMPLATE"
(nil (truncate-lines . nil)))
("CHANGELOG"
(nil (fill-column . 70)
(mode . display-fill-column-indicator))))

View File

@@ -331,6 +331,7 @@ All Contributors
- Rémi Vanicat
- René Stadler
- Richard Kim
- Richard Sent
- Robert Boone
- Robert Irelan
- Robin Green
@@ -408,6 +409,7 @@ All Contributors
- Win Treese
- Wojciech Siewierski
- Wouter Bolsterlee
- X4lldux
- Xavier Noria
- Xu Chunyang
- Yann Herklotz

1224
lisp/magit/git-commit.el Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -44,8 +44,8 @@
;; M-p Move the commit at point up.
;; M-n Move the commit at point down.
;;
;; k Drop the commit at point.
;; c Don't drop the commit at point.
;; d Drop the commit at point.
;; c Keep the commit at point.
;; r Change the message of the commit at point.
;; e Edit the commit at point.
;; s Squash the commit at point, into the one above.
@@ -53,6 +53,7 @@
;; b Break for editing at this point in the sequence.
;; x Add a script to be run with the commit at point
;; being checked out.
;; k Un-/comment current line.
;; z Add noop action at point.
;;
;; SPC Show the commit at point in another buffer.
@@ -152,6 +153,7 @@
"M-p" #'git-rebase-move-line-up
"M-n" #'git-rebase-move-line-down
"c" #'git-rebase-pick
"d" #'git-rebase-drop
"k" #'git-rebase-kill-line
"C-k" #'git-rebase-kill-line
"b" #'git-rebase-break
@@ -160,11 +162,14 @@
"M M" #'git-rebase-merge
"M t" #'git-rebase-merge-toggle-editmsg
"m" #'git-rebase-edit
"s" #'git-rebase-squash
"S" #'git-rebase-squish
"f" #'git-rebase-fixup
"F" #'git-rebase-alter
"A" #'git-rebase-alter
"q" #'undefined
"r" #'git-rebase-reword
"w" #'git-rebase-reword
"s" #'git-rebase-squash
"t" #'git-rebase-reset
"u" #'git-rebase-update-ref
"x" #'git-rebase-exec
@@ -176,6 +181,7 @@
"M-<up>" #'git-rebase-move-line-up
"M-<down>" #'git-rebase-move-line-down
"<remap> <undo>" #'git-rebase-undo)
(put 'git-rebase-alter :advertised-binding (kbd "F"))
(put 'git-rebase-reword :advertised-binding (kbd "r"))
(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p"))
(put 'git-rebase-kill-line :advertised-binding (kbd "k"))
@@ -184,6 +190,7 @@
"Git-Rebase mode menu."
'("Rebase"
["Pick" git-rebase-pick t]
["Drop" git-rebase-drop t]
["Reword" git-rebase-reword t]
["Edit" git-rebase-edit t]
["Squash" git-rebase-squash t]
@@ -208,10 +215,22 @@
(git-rebase-show-commit
. "show the commit at point in another buffer and select its window")
(undo . "undo last change")
(git-rebase-kill-line . "drop the commit at point")
(git-rebase-drop . "drop the commit at point")
(git-rebase-kill-line . "un-/comment current line")
(git-rebase-insert . "insert a line for an arbitrary commit")
(git-rebase-noop . "add noop action at point")))
(defvar git-rebase-fixup-descriptions
'((git-rebase-squish
. "fixup -c <commit> = use commit, but meld into previous commit,\n#\
dropping previous commit's message, and open the editor")
(git-rebase-fixup
. "fixup <commit> = use commit, but meld into previous commit,\n#\
dropping <commit>'s message")
(git-rebase-alter
. "fixup -C <commit> = use commit, but meld into previous commit,\n#\
dropping previous commit's message")))
;;; Commands
(defun git-rebase-pick ()
@@ -220,6 +239,12 @@ If the region is active, act on all lines touched by the region."
(interactive)
(git-rebase-set-action "pick"))
(defun git-rebase-drop ()
"Drop commit on current line.
If the region is active, act on all lines touched by the region."
(interactive)
(git-rebase-set-action "drop"))
(defun git-rebase-reword ()
"Edit message of commit on current line.
If the region is active, act on all lines touched by the region."
@@ -233,21 +258,38 @@ If the region is active, act on all lines touched by the region."
(git-rebase-set-action "edit"))
(defun git-rebase-squash ()
"Meld commit on current line into previous commit, edit message.
"Fold commit on current line into previous commit, edit combined message.
If the region is active, act on all lines touched by the region."
(interactive)
(git-rebase-set-action "squash"))
(defun git-rebase-squish ()
"Fold current into previous commit, discard previous message and edit current.
This is like `git-rebase-squash', except that the other message is kept.
The action indicatore shown in the list commits is \"fixup -c\". If the
region is active, act on all lines touched by the region."
(interactive)
(git-rebase-set-action "fixup -c"))
(defun git-rebase-fixup ()
"Meld commit on current line into previous commit, discard its message.
"Fold commit on current line into previous commit, discard current message.
If the region is active, act on all lines touched by the region."
(interactive)
(git-rebase-set-action "fixup"))
(defun git-rebase-alter ()
"Meld current into previous commit, discard previous message and use current.
This is like `git-rebase-fixup', except that the other message is kept.
The action indicatore shown in the list commits is \"fixup -C\". If the
region is active, act on all lines touched by the region."
(interactive)
(git-rebase-set-action "fixup -C"))
(defvar-local git-rebase-comment-re nil)
(defvar git-rebase-short-options
'((?b . "break")
(?d . "drop")
(?e . "edit")
(?f . "fixup")
(?l . "label")
@@ -275,15 +317,19 @@ If the region is active, act on all lines touched by the region."
(action-options :initarg :action-options :initform nil)
(target :initarg :target :initform nil)
(trailer :initarg :trailer :initform nil)
(comment-p :initarg :comment-p :initform nil)))
(comment-p :initarg :comment-p :initform nil)
(abbrev)))
(defvar git-rebase-line-regexps
`((commit . ,(concat
(regexp-opt '("e" "edit"
"f" "fixup"
"p" "pick"
"r" "reword"
"s" "squash")
(regexp-opt '("d" "drop"
"e" "edit"
"f" "fixup"
"f -C" "fixup -C"
"f -c" "fixup -c"
"p" "pick"
"r" "reword"
"s" "squash")
"\\(?1:")
" \\(?3:[^ \n]+\\) ?\\(?4:.*\\)"))
(exec . "\\(?1:x\\|exec\\) \\(?3:.*\\)")
@@ -300,18 +346,21 @@ If the region is active, act on all lines touched by the region."
" ?\\(?4:.*\\)"))))
;;;###autoload
(defun git-rebase-current-line ()
(defun git-rebase-current-line (&optional batch)
"Parse current line into a `git-rebase-action' instance.
If the current line isn't recognized as a rebase line, an
instance with all nil values is returned."
instance with all nil values is returned, unless optional
BATCH is non-nil, in which case nil is returned. Non-nil
BATCH also ignores commented lines."
(save-excursion
(goto-char (line-beginning-position))
(if-let ((re-start (concat "^\\(?5:" (regexp-quote comment-start)
"\\)? *"))
(type (seq-some (lambda (arg)
(if-let ((re-start (if batch
"^"
(format "^\\(?5:%s\\)? *"
(regexp-quote comment-start))))
(type (seq-some (pcase-lambda (`(,type . ,re))
(let ((case-fold-search nil))
(and (looking-at (concat re-start (cdr arg)))
(car arg))))
(and (looking-at (concat re-start re)) type)))
git-rebase-line-regexps)))
(git-rebase-action
:action-type type
@@ -322,15 +371,16 @@ instance with all nil values is returned."
:target (match-string-no-properties 3)
:trailer (match-string-no-properties 4)
:comment-p (and (match-string 5) t))
;; Use default empty class rather than nil to ease handling.
(git-rebase-action))))
(and (not batch)
;; Use empty object rather than nil to ease handling.
(git-rebase-action)))))
(defun git-rebase-set-action (action)
"Set action of commit line to ACTION.
If the region is active, operate on all lines that it touches.
Otherwise, operate on the current line. As a special case, an
ACTION of nil comments the rebase line, regardless of its action
type."
ACTION of nil comments or uncomments the rebase line, regardless
of its action type."
(pcase (git-rebase-region-bounds t)
(`(,beg ,end)
(let ((end-marker (copy-marker end))
@@ -345,9 +395,11 @@ type."
(let ((inhibit-read-only t))
(magit-delete-line)
(insert (concat action " " target " " trailer "\n"))))
((and action-type (not (or action comment-p)))
((and (not action) action-type)
(let ((inhibit-read-only t))
(insert comment-start " "))
(if comment-p
(delete-region beg (+ beg 2))
(insert comment-start " ")))
(forward-line))
(t
;; In the case of --rebase-merges, commit lines may have
@@ -441,8 +493,8 @@ current line."
(bounds (git-rebase-region-bounds)))
(mapc #'delete-overlay magit-section-highlight-overlays)
(when bounds
(magit-section-make-overlay (car bounds) (cadr bounds)
'magit-section-heading-selection))
(magit-section-highlight-range (car bounds) (cadr bounds)
'magit-section-heading-selection))
(if (and bounds (not magit-section-keep-region-overlay))
(funcall (default-value 'redisplay-unhighlight-region-function) rol)
(funcall (default-value 'redisplay-highlight-region-function)
@@ -453,7 +505,8 @@ current line."
(funcall (default-value 'redisplay-unhighlight-region-function) rol))
(defun git-rebase-kill-line ()
"Kill the current action line.
"Comment the current action line.
If the action line is already commented, then uncomment it.
If the region is active, act on all lines touched by the region."
(interactive)
(git-rebase-set-action nil))
@@ -588,8 +641,7 @@ commit. For an upper-case -C, the message will be used as is."
(insert
(format "merge %s %s %s\n"
(replace-regexp-in-string
"-[cC]" (lambda (c)
(if (equal c "-c") "-C" "-c"))
"-[cC]" (##if (equal % "-c") "-C" "-c")
action-options t t)
target
trailer)))
@@ -770,6 +822,8 @@ running \"man git-rebase\" at the command line) for details."
("^\\(m\\(?:erge\\)?\\) \\([^ \n]+\\)"
(1 'git-rebase-action)
(2 'git-rebase-label))
("^drop \\(.+\\)"
1 'git-rebase-killed-action t)
(,(concat git-rebase-comment-re " *"
(cdr (assq 'commit git-rebase-line-regexps)))
0 'git-rebase-killed-action t)
@@ -799,24 +853,23 @@ except for the \"pick\" command."
(concat git-rebase-comment-re "\\s-+p, pick")
nil t))
(goto-char (line-beginning-position))
(pcase-dolist (`(,cmd . ,desc) git-rebase-command-descriptions)
(insert (format (propertize "%s %s %s\n"
'font-lock-face 'font-lock-comment-face)
comment-start
(string-pad
(substitute-command-keys (format "\\[%s]" cmd)) 8)
desc)))
(while (re-search-forward
(concat git-rebase-comment-re "\\(?:"
"\\( \\.? *\\)\\|"
"\\( +\\)\\([^\n,],\\) \\([^\n ]+\\) \\)")
nil t)
(if (match-string 1)
(replace-match (make-string 10 ?\s) t t nil 1)
(let ((cmd (intern (concat "git-rebase-" (match-string 4)))))
(if (not (fboundp cmd))
(delete-region (line-beginning-position)
(1+ (line-end-position)))
(git-rebase--insert-descriptions git-rebase-command-descriptions)
(let ((cmd nil)
(line (concat git-rebase-comment-re "\\(?:\\( \\.? *\\)\\|"
"\\( +\\)\\([^\n,],\\) \\([^\n ]+\\) \\)")))
(while (re-search-forward line nil t)
(if (match-string 1)
(if (assq cmd git-rebase-fixup-descriptions)
(delete-line)
(replace-match (make-string 10 ?\s) t t nil 1))
(setq cmd (intern (concat "git-rebase-" (match-string 4))))
(cond
((not (fboundp cmd))
(delete-line))
((eq cmd 'git-rebase-fixup)
(delete-line)
(git-rebase--insert-descriptions git-rebase-fixup-descriptions))
(t
(add-text-properties (line-beginning-position)
(1+ (line-end-position))
'(font-lock-face font-lock-comment-face))
@@ -826,7 +879,16 @@ except for the \"pick\" command."
(save-match-data
(substitute-command-keys (format "\\[%s]" cmd)))
8)
t t nil 3)))))))))
t t nil 3))))))))))
(defun git-rebase--insert-descriptions (alist)
(pcase-dolist (`(,cmd . ,desc) alist)
(insert (format (propertize "%s %s %s\n"
'font-lock-face 'font-lock-comment-face)
comment-start
(string-pad
(substitute-command-keys (format "\\[%s]" cmd)) 8)
(replace-regexp-in-string "#" comment-start desc)))))
(add-hook 'git-rebase-mode-hook #'git-rebase-mode-show-keybindings t)

View File

@@ -137,11 +137,9 @@ so causes the change to be applied to the index as well."
(defun magit-apply-diffs (sections &rest args)
(setq sections (magit-apply--get-diffs sections))
(magit-apply-patch sections args
(mapconcat
(lambda (s)
(concat (magit-diff-file-header s)
(magit-apply--section-content s)))
sections "")))
(mapconcat (##concat (magit-diff-file-header %)
(magit-apply--section-content %))
sections "")))
(defun magit-apply-diff (section &rest args)
(setq section (car (magit-apply--get-diffs (list section))))
@@ -222,6 +220,7 @@ adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
(command (if (and command (string-match "^magit-\\([^-]+\\)" command))
(match-string 1 command)
"apply"))
(context (magit-diff-get-context))
(ignore-context (magit-diff-ignore-any-space-p)))
(unless (magit-diff-context-p)
(user-error "Not enough context to apply patch. Increase the context"))
@@ -229,10 +228,11 @@ adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
(magit-wip-commit-before-change files (concat " before " command)))
(with-temp-buffer
(insert patch)
(magit-run-git-with-input
"apply" args "-p0"
(and ignore-context "-C0")
"--ignore-space-change" "-"))
(let ((magit-inhibit-refresh t))
(magit-run-git-with-input
"apply" args "-p0"
(if ignore-context "-C0" (format "-C%s" context))
"--ignore-space-change" "-")))
(unless magit-inhibit-refresh
(when magit-wip-after-apply-mode
(magit-wip-commit-after-apply files (concat " after " command)))
@@ -243,9 +243,10 @@ adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
(let ((section (magit-current-section)))
(pcase (oref section type)
((or 'hunk 'file 'module) section)
((or 'staged 'unstaged 'untracked
((or 'staged 'unstaged
'stashed-index 'stashed-worktree 'stashed-untracked)
(oref section children))
('untracked t)
(_ (user-error "Cannot apply this, it's not a change"))))))
(defun magit-apply--get-diffs (sections)
@@ -273,8 +274,7 @@ return nil, possibly causing whitespace changes to be applied."
"--ignore-all-space"
"--ignore-blank-lines")))
magit-buffer-diff-args)
(not (cl-find-if (lambda (section)
(oref section binary))
(not (cl-find-if (##oref % binary)
(ensure-list selection)))))
;;;; Stage
@@ -303,23 +303,10 @@ at point, stage the file but not its content."
(`(staged ,_ ,_) (user-error "Already staged"))
(`(committed ,_ ,_) (user-error "Cannot stage committed changes"))
(`(undefined ,_ ,_) (user-error "Cannot stage this change")))
(call-interactively #'magit-stage-file)))
(call-interactively #'magit-stage-files)))
;;;###autoload
(defun magit-stage-buffer-file ()
"Stage all changes to the file being visited in the current buffer."
(interactive)
(unless buffer-file-name
(user-error "Not visiting a file"))
(magit-with-toplevel
(magit-stage-1 (and (magit-file-ignored-p buffer-file-name)
(if (y-or-n-p "Visited file is ignored; stage anyway?")
"--force"
(user-error "Abort")))
(list (magit-file-relative-name)))))
;;;###autoload
(defun magit-stage-file (files &optional force)
(defun magit-stage-files (files &optional force)
"Read one or more files and stage all changes in those files.
With prefix argument FORCE, offer ignored files for completion."
(interactive
@@ -335,10 +322,7 @@ With prefix argument FORCE, offer ignored files for completion."
choices nil t nil nil default)
current-prefix-arg)))
(magit-with-toplevel
;; For backward compatibility, and because of
;; the function's name, don't require a list.
(magit-stage-1 (and force "--force")
(ensure-list files))))
(magit-stage-1 (and force "--force") files)))
;;;###autoload
(defun magit-stage-modified (&optional all)
@@ -408,9 +392,9 @@ ignored) files."
(defvar magit-post-stage-hook-commands
(list #'magit-stage
#'magit-stage-buffer-file
#'magit-stage-file
#'magit-stage-modified))
#'magit-stage-files
#'magit-stage-modified
'magit-file-stage))
(defun magit-run-post-stage-hook ()
(when (memq this-command magit-post-stage-hook-commands)
@@ -445,16 +429,7 @@ ignored) files."
(`(undefined ,_ ,_) (user-error "Cannot unstage this change")))))
;;;###autoload
(defun magit-unstage-buffer-file ()
"Unstage all changes to the file being visited in the current buffer."
(interactive)
(unless buffer-file-name
(user-error "Not visiting a file"))
(magit-with-toplevel
(magit-unstage-1 (list (magit-file-relative-name)))))
;;;###autoload
(defun magit-unstage-file (files)
(defun magit-unstage-files (files)
"Read one or more files and unstage all changes to those files."
(interactive
(let* ((choices (magit-staged-files))
@@ -464,9 +439,7 @@ ignored) files."
(list (magit-completing-read-multiple "Unstage file,s: " choices
nil t nil nil default))))
(magit-with-toplevel
;; For backward compatibility, and because of
;; the function's name, don't require a list.
(magit-unstage-1 (ensure-list files))))
(magit-unstage-1 files)))
(defun magit-unstage-1 (files)
(magit-wip-commit-before-change files " before unstage")
@@ -496,9 +469,9 @@ ignored) files."
(defvar magit-post-unstage-hook-commands
(list #'magit-unstage
#'magit-unstage-buffer-file
#'magit-unstage-file
#'magit-unstage-all))
#'magit-unstage-files
#'magit-unstage-all
'magit-file-unstage))
(defun magit-run-post-unstage-hook ()
(when (memq this-command magit-post-unstage-hook-commands)
@@ -515,14 +488,18 @@ of a side, then keep that side without prompting."
(interactive)
(when-let ((s (magit-apply--get-selection)))
(pcase (list (magit-diff-type) (magit-diff-scope))
(`(committed ,_) (user-error "Cannot discard committed changes"))
(`(undefined ,_) (user-error "Cannot discard this change"))
(`(,_ region) (magit-discard-region s))
(`(,_ hunk) (magit-discard-hunk s))
(`(,_ hunks) (magit-discard-hunks s))
(`(,_ file) (magit-discard-file s))
(`(,_ files) (magit-discard-files s))
(`(,_ list) (magit-discard-files s)))))
(`(committed ,_) (user-error "Cannot discard committed changes"))
(`(undefined ,_) (user-error "Cannot discard this change"))
(`(untracked list) (magit-discard-files--delete
(magit-with-toplevel
(magit-untracked-files nil nil "--directory"))
nil))
(`(,_ region) (magit-discard-region s))
(`(,_ hunk) (magit-discard-hunk s))
(`(,_ hunks) (magit-discard-hunks s))
(`(,_ file) (magit-discard-file s))
(`(,_ files) (magit-discard-files s))
(`(,_ list) (magit-discard-files s)))))
(defun magit-discard-region (section)
(magit-confirm 'discard "Discard region")
@@ -623,9 +600,7 @@ of a side, then keep that side without prompting."
(magit-read-char-case
(format "For these %d files\n%s\ncheckout:\n"
(length files)
(mapconcat (lambda (file)
(concat " " file))
files "\n"))
(mapconcat (##concat " " %) files "\n"))
t
(?o "[o]ur stage" "--ours")
(?t "[t]heir stage" "--theirs")

View File

@@ -69,21 +69,17 @@
(defcustom magit-completing-read-function #'magit-builtin-completing-read
"Function to be called when requesting input from the user.
If you have enabled `ivy-mode' or `helm-mode', then you don't
have to customize this option; `magit-builtin-completing-read'
will work just fine. However, if you use Ido completion, then
you do have to use `magit-ido-completing-read', because Ido is
less well behaved than the former, more modern alternatives.
The default, `magit-builtin-completing-read', support third-party
completion frameworks, including `vertico-mode', `ivy-mode' and
`helm-mode'.
If you would like to use Ivy or Helm completion with Magit but
not enable the respective modes globally, then customize this
option to use `ivy-completing-read' or
`helm--completing-read-default'. If you choose to use
`ivy-completing-read', note that the items may always be shown in
alphabetical order, depending on your version of Ivy."
However, if you would like to use Ivy or Helm completion with Magit but
not enable the respective modes globally, then customize this option to
use `ivy-completing-read' or `helm--completing-read-default'.
If you still use `ido-mode', you'll likely need the `magit-ido' package."
:group 'magit-essentials
:type `(radio (function-item ,#'magit-builtin-completing-read)
(function-item ,#'magit-ido-completing-read)
(function-item ivy-completing-read)
(function-item helm--completing-read-default)
(function :tag "Other function")))
@@ -486,7 +482,9 @@ and delay of your graphical environment or operating system."
((keymap :initform 'magit-file-section-map)
(source :initform nil :initarg :source)
(header :initform nil :initarg :header)
(binary :initform nil :initarg :binary)))
(binary :initform nil :initarg :binary)
(heading-highlight-face :initform 'magit-diff-file-heading-highlight)
(heading-selection-face :initform 'magit-diff-file-heading-selection)))
(defclass magit-module-section (magit-file-section)
((keymap :initform 'magit-module-section-map)
@@ -494,12 +492,15 @@ and delay of your graphical environment or operating system."
(defclass magit-hunk-section (magit-diff-section)
((keymap :initform 'magit-hunk-section-map)
(painted :initform nil)
(refined :initform nil)
(combined :initform nil :initarg :combined)
(from-range :initform nil :initarg :from-range)
(from-ranges :initform nil)
(to-range :initform nil :initarg :to-range)
(about :initform nil :initarg :about)))
(about :initform nil :initarg :about)
(heading-highlight-face :initform 'magit-diff-hunk-heading-highlight)
(heading-selection-face :initform 'magit-diff-hunk-heading-selection)))
(setf (alist-get 'file magit--section-type-alist) 'magit-file-section)
(setf (alist-get 'module magit--section-type-alist) 'magit-module-section)
@@ -604,21 +605,21 @@ acts similarly to `completing-read', except for the following:
def)
(unless def
(setq def fallback))
(when (and def
(not (functionp collection))
(not (member def collection)))
(setq collection (cons def collection)))
(let ((command this-command)
(reply (funcall
magit-completing-read-function
(magit--format-prompt prompt def)
(if (and (not (functionp collection))
def
(not (member def collection)))
(cons def collection)
collection)
predicate
require-match initial-input hist def)))
(reply (funcall magit-completing-read-function
(magit--format-prompt prompt def)
collection predicate
require-match initial-input hist def)))
(setq this-command command)
;; Note: Avoid `string=' to support `helm-comp-read-use-marked'.
(if (equal reply "")
(if require-match
(if (and require-match
(not (and (listp collection)
(member "" collection))))
(user-error "Nothing selected")
nil)
reply))))
@@ -642,9 +643,13 @@ acts similarly to `completing-read', except for the following:
(unless (or (bound-and-true-p helm-mode)
(bound-and-true-p ivy-mode))
(setq choices (magit--completion-table choices)))
(let ((ivy-sort-functions-alist nil)
(vertico-sort-function nil))
(completing-read prompt choices
(let ((ivy-sort-functions-alist nil))
(completing-read prompt
(lambda (str pred action)
(if (eq action 'metadata)
'(metadata (display-sort-function . identity)
(cycle-sort-function . identity))
(complete-with-action action choices str pred)))
predicate require-match
initial-input hist def)))
@@ -695,27 +700,6 @@ third-party completion frameworks."
hist def inherit-input-method)))
(if no-split input values)))
(defun magit-ido-completing-read
(prompt choices &optional predicate require-match initial-input hist def)
"Ido-based `completing-read' almost-replacement.
Unfortunately `ido-completing-read' is not suitable as a
drop-in replacement for `completing-read', instead we use
`ido-completing-read+' from the third-party package by the
same name."
(if (and (require 'ido-completing-read+ nil t)
(fboundp 'ido-completing-read+))
(ido-completing-read+ prompt choices predicate require-match
initial-input hist
(or def (and require-match (car choices))))
(display-warning 'magit "ido-completing-read+ is not installed
To use Ido completion with Magit you need to install the
third-party `ido-completing-read+' packages. Falling
back to built-in `completing-read' for now." :error)
(magit-builtin-completing-read prompt choices predicate require-match
initial-input hist def)))
(defvar-keymap magit-minibuffer-local-ns-map
:parent minibuffer-local-map
"SPC" #'magit-whitespace-disallowed
@@ -804,12 +788,12 @@ ACTION is a member of option `magit-slow-confirm'."
(when (and prompt (listp prompt))
(setq prompt
(apply #'format (car prompt)
(mapcar (lambda (a) (if (stringp a) (string-replace "%" "%%" a) a))
(mapcar (##if (stringp %) (string-replace "%" "%%" %) %)
(cdr prompt)))))
(when (and prompt-n (listp prompt-n))
(setq prompt-n
(apply #'format (car prompt-n)
(mapcar (lambda (a) (if (stringp a) (string-replace "%" "%%" a) a))
(mapcar (##if (stringp %) (string-replace "%" "%%" %) %)
(cdr prompt-n)))))
(setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items)))
(setq prompt (format (concat (or prompt (magit-confirm-make-prompt action))
@@ -874,7 +858,7 @@ See info node `(magit)Debugging Tools' for more information."
`(,(concat invocation-directory invocation-name)
"-Q" "--eval" "(setq debug-on-error t)"
,@(mapcan
(lambda (dir) (list "-L" dir))
(##list "-L" %)
(delete-dups
(mapcan
(lambda (lib)
@@ -1043,7 +1027,7 @@ This function should be named `version>=' and be part of Emacs."
;;; Kludges for Emacs Bugs
(defun magit-which-function ()
"Return current function name based on point.
"Return current function name based on point, without caching.
This is a simple wrapper around `which-function', that resets
Imenu's potentially outdated and therefore unreliable cache by

View File

@@ -62,7 +62,7 @@
["Arguments"
("-n" "Don't checkout commits" "--no-checkout")
("-p" "Follow only first parent of a merge" "--first-parent"
:if (lambda () (magit-git-version>= "2.29")))
:if (##magit-git-version>= "2.29"))
(magit-bisect:--term-old :level 6)
(magit-bisect:--term-new :level 6)]
["Actions"

View File

@@ -94,12 +94,17 @@ The following %-specs can be used in `heading-format' and
`margin-format':
%H hash using face `magit-blame-hash'
%h truncated hash using face `magit-blame-hash'
%s summary using face `magit-blame-summary'
%a author using face `magit-blame-name'
%A author time using face `magit-blame-date'
%c committer using face `magit-blame-name'
%C committer time using face `magit-blame-date'
Note that for performance reasons %h results in truncated
hashes, as opposed to properly abbreviated hashes that are
guaranteed to uniquely identify a commit.
Additionally if `margin-format' ends with %f, then the string
that is displayed in the margin is made at least `margin-width'
characters wide, which may be desirable if the used face sets
@@ -343,8 +348,7 @@ in `magit-blame-read-only-mode-map' instead."
(unless magit-blame--style
(setq magit-blame--style (car magit-blame-styles)))
(setq magit-blame--make-margin-overlays
(and (cl-find-if (lambda (style)
(assq 'margin-format (cdr style)))
(and (cl-find-if (##assq 'margin-format (cdr %))
magit-blame-styles)))
(magit-blame--update-margin 'enable))
(t
@@ -702,6 +706,7 @@ modes is toggled, then this mode also gets toggled automatically.
(cdr (assoc k2 revinfo)))
f)))
`((?H . ,(p0 rev 'magit-blame-hash))
(?h . ,(p0 (magit-blame--abbrev-hash rev) 'magit-blame-hash))
(?s . ,(p1 "summary" 'magit-blame-summary))
(?a . ,(p1 "author" 'magit-blame-name))
(?c . ,(p1 "committer" 'magit-blame-name))
@@ -732,6 +737,13 @@ modes is toggled, then this mode also gets toggled automatically.
(seconds-to-time (string-to-number time))
tz-in-second)))
(defvar-local magit-blame--abbrev-length nil)
(defun magit-blame--abbrev-hash (rev)
(substring rev 0 (or magit-blame--abbrev-length
(setq magit-blame--abbrev-length
(magit-abbrev-length)))))
(defun magit-blame--remove-overlays (&optional beg end)
(save-restriction
(widen)
@@ -758,10 +770,9 @@ modes is toggled, then this mode also gets toggled automatically.
Show the information about the chunk at point in the echo area
when moving between chunks. Unlike other blaming commands, do
not turn on `read-only-mode'."
:if (lambda ()
(and buffer-file-name
:if (##and buffer-file-name
(or (not magit-blame-mode)
buffer-read-only)))
buffer-read-only))
(interactive (list (magit-blame-arguments)))
(when magit-buffer-file-name
(user-error "Blob buffers aren't supported"))

View File

@@ -37,6 +37,11 @@
(cl-defmethod magit-bookmark-get-filename (&context (major-mode magit-mode))
(magit-toplevel))
(cl-defmethod magit-bookmark-get-value
(bookmark &context (major-mode magit-mode))
(dolist (var (get major-mode 'magit-bookmark-variables))
(bookmark-prop-set bookmark var (symbol-value var))))
(cl-defmethod magit-bookmark-get-buffer-create
(bookmark (mode (derived-mode magit-mode)))
(let ((default-directory (bookmark-get-filename bookmark))

View File

@@ -208,11 +208,10 @@ has to be used to view and change branch related variables."
(transient-define-prefix magit-branch (branch)
"Add, configure or remove a branch."
:man-page "git-branch"
[:if (lambda () (and magit-branch-direct-configure (transient-scope)))
:description
(lambda ()
(concat (propertize "Configure " 'face 'transient-heading)
(propertize (transient-scope) 'face 'magit-branch-local)))
[:if (##and magit-branch-direct-configure (transient-scope))
:description (##concat
(propertize "Configure " 'face 'transient-heading)
(propertize (transient-scope) 'face 'magit-branch-local))
("d" magit-branch.<branch>.description)
("u" magit-branch.<branch>.merge/remote)
("r" magit-branch.<branch>.rebase)
@@ -813,11 +812,13 @@ the remote."
;;;###autoload
(defun magit-branch-shelve (branch)
"Shelve a BRANCH.
Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\",
Rename \"refs/heads/BRANCH\" to \"refs/shelved/YYYY-MM-DD-BRANCH\",
and also rename the respective reflog file."
(interactive (list (magit-read-other-local-branch "Shelve branch")))
(let ((old (concat "refs/heads/" branch))
(new (concat "refs/shelved/" branch)))
(let ((old (concat "refs/heads/" branch))
(new (format "refs/shelved/%s-%s"
(magit-rev-format "%cs" branch)
branch)))
(magit-git "update-ref" new old "")
(magit--rename-reflog-file old new)
(magit-branch-unset-pushRemote branch)
@@ -826,16 +827,21 @@ and also rename the respective reflog file."
;;;###autoload
(defun magit-branch-unshelve (branch)
"Unshelve a BRANCH.
Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\",
and also rename the respective reflog file."
Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\". If BRANCH
is prefixed with \"YYYY-MM-DD\", then drop that part of the name.
Also rename the respective reflog file."
(interactive
(list (magit-completing-read
"Unshelve branch"
(mapcar (##substring % 8)
(magit-list-refnames "refs/shelved"))
(nreverse (magit-list-refnames "refs/shelved")))
nil t)))
(let ((old (concat "refs/shelved/" branch))
(new (concat "refs/heads/" branch)))
(new (concat "refs/heads/"
(if (string-match-p
"\\`[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}-" branch)
(substring branch 11)
branch))))
(magit-git "update-ref" new old "")
(magit--rename-reflog-file old new)
(magit-run-git "update-ref" "-d" old)))
@@ -854,10 +860,9 @@ and also rename the respective reflog file."
(transient-define-prefix magit-branch-configure (branch)
"Configure a branch."
:man-page "git-branch"
[:description
(lambda ()
(concat (propertize "Configure " 'face 'transient-heading)
(propertize (transient-scope) 'face 'magit-branch-local)))
[:description (##concat
(propertize "Configure " 'face 'transient-heading)
(propertize (transient-scope) 'face 'magit-branch-local))
("d" magit-branch.<branch>.description)
("u" magit-branch.<branch>.merge/remote)
("r" magit-branch.<branch>.rebase)

View File

@@ -50,7 +50,7 @@
(declare-function magit-blame-mode "magit-blame" (&optional arg))
(defvar magit-blame-mode)
;; For `magit-diff-show-or-scroll'
(declare-function git-rebase-current-line "git-rebase" ())
(declare-function git-rebase-current-line "git-rebase" (&optional batch))
;; For `magit-diff-unmerged'
(declare-function magit-merge-in-progress-p "magit-merge" ())
(declare-function magit--merge-range "magit-merge" (&optional head))
@@ -73,7 +73,7 @@
(declare-function magit-commit-add-log "magit-commit" ())
(declare-function magit-diff-trace-definition "magit-log" ())
(declare-function magit-patch-save "magit-patch" (files &optional arg))
(declare-function magit-do-async-shell-command "magit-extras" (file))
(declare-function magit-do-async-shell-command "magit-dired" (file))
(declare-function magit-add-change-log-entry "magit-extras"
(&optional whoami file-name other-window))
(declare-function magit-add-change-log-entry-other-window "magit-extras"
@@ -141,9 +141,7 @@ to have any effect."
:type 'float)
(defcustom magit-diff-highlight-hunk-body t
"Whether to highlight bodies of selected hunk sections.
This only has an effect if `magit-diff-highlight' is a
member of `magit-section-highlight-hook', which see."
"Whether to highlight bodies of selected hunk sections."
:package-version '(magit . "2.1.0")
:group 'magit-diff
:type 'boolean)
@@ -194,13 +192,16 @@ keep their distinct foreground colors."
"Whether to show word-granularity differences within diff hunks.
`nil' Never show fine differences.
`t' Show fine differences for the current diff hunk only.
`all' Show fine differences for all displayed diff hunks."
`all' Show fine differences for all displayed diff hunks.
`t' Refine each hunk once it becomes the current section.
Keep the refinement when another section is selected.
Refreshing the buffer removes all refinement. This
variant is only provided for performance reasons."
:group 'magit-diff
:safe (lambda (val) (memq val '(nil t all)))
:type '(choice (const :tag "Never" nil)
(const :tag "Current" t)
(const :tag "All" all)))
:safe (##memq % '(nil t all))
:type '(choice (const :tag "No refinement" nil)
(const :tag "Immediately refine all hunks" all)
(const :tag "Refine each hunk when moving to it" t)))
(defcustom magit-diff-refine-ignore-whitespace smerge-refine-ignore-whitespace
"Whether to ignore whitespace changes in word-granularity differences."
@@ -258,7 +259,7 @@ The options `magit-diff-highlight-trailing' and
`magit-diff-highlight-indentation' control what kind of
whitespace errors are highlighted."
:group 'magit-diff
:safe (lambda (val) (memq val '(t nil uncommitted status)))
:safe (##memq % '(t nil uncommitted status))
:type '(choice (const :tag "In all diffs" t)
(const :tag "Only in uncommitted changes" uncommitted)
(const :tag "Never" nil)))
@@ -271,7 +272,7 @@ whitespace errors are highlighted."
`all' Highlight in added, removed and context lines."
:package-version '(magit . "3.0.0")
:group 'magit-diff
:safe (lambda (val) (memq val '(t both all)))
:safe (##memq % '(t both all))
:type '(choice (const :tag "In added lines" t)
(const :tag "In added and removed lines" both)
(const :tag "In added, removed and context lines" all)))
@@ -332,10 +333,10 @@ it receives either three or five arguments; the signature has to be
`module', `stat' and `list'."
:package-version '(magit . "4.3.1")
:group 'magit-diff
:type `(choice (function-item ,#'magit-format-file-default)
(function-item ,#'magit-format-file-all-the-icons)
(function-item ,#'magit-format-file-nerd-icons)
function))
:type `(radio (function-item ,#'magit-format-file-default)
(function-item ,#'magit-format-file-all-the-icons)
(function-item ,#'magit-format-file-nerd-icons)
function))
;;;; File Diff
@@ -897,37 +898,35 @@ and `:slant'."
;;; Commands
;;;; Prefix Commands
(eval-and-compile
(defvar magit-diff-infix-arguments
[:class transient-subgroups
["Limit arguments"
(magit:--)
(magit-diff:--ignore-submodules)
("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
("-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))
("-D" "Omit preimage for deletes" ("-D" "--irreversible-delete")
:level 5)]
["Context arguments"
(magit-diff:-U)
("-W" "Show surrounding functions" ("-W" "--function-context"))]
["Tune arguments"
(magit-diff:--diff-algorithm)
(magit-diff:--diff-merges)
(magit-diff:-M)
(magit-diff:-C)
(magit-diff:-R :level 5)
(magit-diff:--color-moved :level 5)
(magit-diff:--color-moved-ws :level 5)
(magit-diff:--no-ext-diff)
(magit-diff:--stat)
(magit-diff:--show-signature)]]))
(transient-define-group magit-diff-infix-arguments
["Limit arguments"
(magit:--)
(magit-diff:--ignore-submodules)
("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
("-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))
("-D" "Omit preimage for deletes" ("-D" "--irreversible-delete")
:level 5)]
["Context arguments"
(magit-diff:-U)
("-W" "Show surrounding functions" ("-W" "--function-context"))]
["Tune arguments"
(magit-diff:--diff-algorithm)
(magit-diff:--diff-merges)
(magit-diff:-M)
(magit-diff:-C)
(magit-diff:-R :level 5)
(magit-diff:--color-moved :level 5)
(magit-diff:--color-moved-ws :level 5)
(magit-diff:--no-ext-diff)
(magit-diff:--stat)
(magit-diff:--show-signature)])
;;;###autoload (autoload 'magit-diff "magit-diff" nil t)
(transient-define-prefix magit-diff ()
"Show changes between different versions."
:man-page "git-diff"
:class 'magit-diff-prefix
[magit-diff-infix-arguments]
'magit-diff-infix-arguments
["Actions"
[("d" "Dwim" magit-diff-dwim)
("r" "Diff range" magit-diff-range)
@@ -943,7 +942,7 @@ and `:slant'."
"Change the arguments used for the diff(s) in the current buffer."
:man-page "git-diff"
:class 'magit-diff-refresh-prefix
[magit-diff-infix-arguments]
'magit-diff-infix-arguments
[["Refresh"
("g" "buffer" magit-diff-refresh)
("s" "buffer and set defaults" transient-set-and-exit)
@@ -1406,7 +1405,7 @@ for a revision."
(magit-section-parent-value (magit-current-section))))))
(require 'magit)
(let* ((file (magit-file-relative-name))
(ln (and file (line-number-at-pos))))
(line (and file (line-number-at-pos))))
(magit-with-toplevel
(when module
(setq default-directory
@@ -1417,15 +1416,14 @@ for a revision."
(save-buffer))
(let ((buf (magit-revision-setup-buffer rev args files)))
(when file
(let ((line (magit-diff-visit--offset file (list "-R" rev) ln))
(let ((line (magit-diff-visit--offset file (list "-R" rev) line))
(col (current-column)))
(with-current-buffer buf
(magit-diff--goto-position file line col))))))))
(defun magit-diff--locate-hunk (file line &optional parent)
(and-let* ((diff (cl-find-if (lambda (section)
(and (cl-typep section 'magit-file-section)
(equal (oref section value) file)))
(and-let* ((diff (cl-find-if (##and (cl-typep % 'magit-file-section)
(equal (oref % value) file))
(oref (or parent magit-root-section) children))))
(let ((hunks (oref diff children)))
(cl-block nil
@@ -1458,7 +1456,6 @@ for a revision."
(when (oref section hidden)
(magit-section-show section))
(setq section (oref section parent))))
(magit-section-update-highlight)
t))
;;;; Setting Commands
@@ -1522,12 +1519,12 @@ instead."
(defun magit-diff-less-context (&optional count)
"Decrease the context for diff hunks by COUNT lines."
(interactive "p")
(magit-diff-set-context (lambda (cur) (max 0 (- (or cur 0) count)))))
(magit-diff-set-context (##max 0 (- (or % 0) count))))
(defun magit-diff-more-context (&optional count)
"Increase the context for diff hunks by COUNT lines."
(interactive "p")
(magit-diff-set-context (lambda (cur) (+ (or cur 0) count))))
(magit-diff-set-context (##+ (or % 0) count)))
(defun magit-diff-default-context ()
"Reset context for diff hunks to the default height."
@@ -1552,6 +1549,14 @@ instead."
(setq magit-buffer-diff-args val))
(magit-refresh))
(defun magit-diff-get-context ()
(string-to-number
(or (seq-some (##and (string-match "\\`-U\\([0-9]+\\)?\\'" %)
(match-string 1 %))
magit-buffer-diff-args)
(magit-get "diff.context")
"3")))
(defun magit-diff-context-p ()
(if-let ((arg (seq-find (##string-match "^-U\\([0-9]+\\)$" %)
magit-buffer-diff-args)))
@@ -1597,9 +1602,9 @@ Display the buffer in the selected window. With a prefix
argument OTHER-WINDOW display the buffer in another window
instead.
Visit the worktree version of the appropriate file. The location
of point inside the diff determines which file is being visited.
The visited version depends on what changes the diff is about.
The location of point inside the diff determines which file is
being visited. The visited version depends on what changes the
diff is about.
1. If the diff shows uncommitted changes (i.e., stage or unstaged
changes), then visit the file in the working tree (i.e., the
@@ -2125,8 +2130,8 @@ keymap is the parent of their keymaps."
"<remap> <magit-visit-thing>" #'magit-diff-visit-file
"<remap> <magit-revert-no-commit>" #'magit-reverse
"<remap> <magit-delete-thing>" #'magit-discard
"<remap> <magit-unstage-file>" #'magit-unstage
"<remap> <magit-stage-file>" #'magit-stage
"<remap> <magit-unstage-files>" #'magit-unstage
"<remap> <magit-stage-files>" #'magit-stage
"<remap> <magit-cherry-apply>" #'magit-apply
"<8>" (magit-menu-item "Rename file" #'magit-file-rename
'(:enable (eq (magit-diff-scope) 'file)))
@@ -2232,7 +2237,7 @@ keymap is the parent of their keymaps."
(unless (equal cmd "merge-tree")
(push "--ita-visible-in-index" args))
(setq args (magit-diff--maybe-add-stat-arguments args))
(when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args)
(when (cl-member-if (##string-prefix-p "--color-moved" %) args)
(push "--color=always" args)
(setq magit-git-global-arguments
(append magit-diff--reset-non-color-moved
@@ -2240,7 +2245,7 @@ keymap is the parent of their keymaps."
(magit--git-wash #'magit-diff-wash-diffs
(if (member "--no-index" args)
'wash-anyway
(or keep-error magit--git-wash-keep-error))
(or keep-error t))
cmd args)))
(defun magit-diff--maybe-add-stat-arguments (args)
@@ -2339,7 +2344,7 @@ keymap is the parent of their keymaps."
(if (looking-at "^$") (forward-line) (insert "\n"))))))
(defun magit-diff-wash-diff (args)
(when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args)
(when (cl-member-if (##string-prefix-p "--color-moved" %) args)
(require 'ansi-color)
(ansi-color-apply-on-region (point-min) (point-max)))
(cond
@@ -2454,7 +2459,7 @@ keymap is the parent of their keymaps."
(setq header (nreverse header))
;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used.
(when (and (derived-mode-p 'magit-log-mode)
(seq-some (lambda (arg) (string-prefix-p "-L" arg))
(seq-some (##string-prefix-p "-L" %)
magit-buffer-log-args))
(when orig
(setq orig (substring orig 2)))
@@ -2498,11 +2503,15 @@ keymap is the parent of their keymaps."
(funcall magit-format-file-function kind file face status orig))
(defun magit-format-file-default (_kind file face &optional status orig)
"Show only the Git status and the filename."
(propertize (concat (and status (format "%-11s" status))
(if orig (format "%s -> %s" orig file) file))
'font-lock-face face))
(defun magit-format-file-all-the-icons (kind file face &optional status orig)
"Show the status, filename and icon (using the `all-the-icons' package).
You have to explicitly install the `all-the-icons' package, else this
function errors."
(cl-flet ((icon (if (or (eq kind 'module) (string-suffix-p "/" file))
'all-the-icons-icon-for-dir
'all-the-icons-icon-for-file)))
@@ -2519,6 +2528,9 @@ keymap is the parent of their keymaps."
'font-lock-face face))))
(defun magit-format-file-nerd-icons (kind file face &optional status orig)
"Show the status, filename and icon (using the `nerd-icons' package).
You have to explicitly install the `nerd-icons' package, else this
function errors."
(cl-flet ((icon (if (or (eq kind 'module) (string-suffix-p "/" file))
'nerd-icons-icon-for-dir
'nerd-icons-icon-for-file)))
@@ -2616,7 +2628,6 @@ keymap is the parent of their keymaps."
(magit-delete-line)
(magit-insert-section
( hunk value nil
:washer #'magit-diff-paint-hunk
:combined combined
:from-range (if combined (butlast ranges) (car ranges))
:to-range (car (last ranges))
@@ -2631,7 +2642,7 @@ keymap is the parent of their keymaps."
(defun magit-diff-expansion-threshold (section)
"Keep new diff sections collapsed if washing takes too long."
(and (magit-file-section-p section)
(> (float-time (time-since magit-refresh-start-time))
(> (float-time (time-since magit--refresh-start-time))
magit-diff-expansion-threshold)
'hide))
@@ -2877,10 +2888,10 @@ or a ref which is not a branch, then it inserts nothing."
(defun magit-insert-revision-headers ()
"Insert headers about the commit into a revision buffer."
(magit-insert-section (headers)
(magit-insert-heading
(magit-insert-heading nil
(and-let* ((string (magit-rev-format "%D" magit-buffer-revision
"--decorate=full")))
(magit-format-ref-labels string) ?\s)
(concat (magit-format-ref-labels string) " "))
(propertize
(magit-rev-parse (magit--rev-dereference magit-buffer-revision))
'font-lock-face 'magit-hash))
@@ -2936,18 +2947,18 @@ Refer to user option `magit-revision-insert-related-refs-display-alist'."
(defun magit--insert-related-refs (rev arg title remote)
(when-let ((refs (magit-list-related-branches arg rev (and remote "-a"))))
(insert title ":" (make-string (- 10 (length title)) ?\s))
(dolist (branch refs)
(if (<= (+ (current-column) 1 (length branch))
(window-width))
(insert ?\s)
(insert ?\n (make-string 12 ?\s)))
(magit-insert-section (branch branch)
(magit-insert-section (related-refs)
(insert title ":" (make-string (- 10 (length title)) ?\s))
(dolist (branch refs)
(if (<= (+ (current-column) 1 (length branch))
(window-width))
(insert ?\s)
(insert ?\n (make-string 12 ?\s)))
(insert (propertize branch 'font-lock-face
(if (string-prefix-p "remotes/" branch)
'magit-branch-remote
'magit-branch-local)))))
(insert ?\n)))
'magit-branch-local))))
(insert ?\n))))
(defun magit-insert-revision-gravatars (rev beg)
(when (and magit-revision-show-gravatars
@@ -3100,7 +3111,7 @@ It the SECTION has a different type, then do nothing."
(defvar-keymap magit-unstaged-section-map
:doc "Keymap for the `unstaged' section."
"<remap> <magit-visit-thing>" #'magit-diff-unstaged
"<remap> <magit-stage-file>" #'magit-stage
"<remap> <magit-stage-files>" #'magit-stage
"<remap> <magit-delete-thing>" #'magit-discard
"<3>" (magit-menu-item "Discard all" #'magit-discard)
"<2>" (magit-menu-item "Stage all" #'magit-stage)
@@ -3121,7 +3132,7 @@ It the SECTION has a different type, then do nothing."
:doc "Keymap for the `staged' section."
"<remap> <magit-revert-no-commit>" #'magit-reverse
"<remap> <magit-delete-thing>" #'magit-discard
"<remap> <magit-unstage-file>" #'magit-unstage
"<remap> <magit-unstage-files>" #'magit-unstage
"<remap> <magit-visit-thing>" #'magit-diff-staged
"<4>" (magit-menu-item "Reverse all" #'magit-reverse)
"<3>" (magit-menu-item "Discard all" #'magit-discard)
@@ -3243,12 +3254,12 @@ actually a `diff' but a `diffstat' section."
(and siblings t)
(magit-diff-use-hunk-region-p)
ssection)
(`(hunk nil t ,_)
(`(hunk nil t ,_)
(if (magit-section-internal-region-p section) 'region 'hunk))
('(hunk t t nil) 'hunks)
(`(hunk ,_ ,_ ,_) 'hunk)
('(file t t nil) 'files)
(`(file ,_ ,_ ,_) 'file)
('(hunk t t nil) 'hunks)
(`(hunk ,_ ,_ ,_) 'hunk)
('(file t t nil) 'files)
(`(file ,_ ,_ ,_) 'file)
('(module t t nil) 'files)
(`(module ,_ ,_ ,_) 'file)
(`(,(or 'staged 'unstaged 'untracked) nil ,_ ,_) 'list)))))
@@ -3265,159 +3276,53 @@ actually a `diff' but a `diffstat' section."
(byte-code-function-p last-command))
(eq (region-end) (region-beginning))))))
;;; Diff Highlight
(add-hook 'magit-section-unhighlight-hook #'magit-diff-unhighlight)
(add-hook 'magit-section-highlight-hook #'magit-diff-highlight)
(defun magit-diff-unhighlight (section selection)
"Remove the highlighting of the diff-related SECTION."
(when (magit-hunk-section-p section)
(magit-diff-paint-hunk section selection nil)
t))
(defun magit-diff-highlight (section selection)
"Highlight the diff-related SECTION.
If SECTION is not a diff-related section, then do nothing and
return nil. If SELECTION is non-nil, then it is a list of sections
selected by the region, including SECTION. All of these sections
are highlighted."
(if (and (magit-section-match 'commit section)
(oref section children))
(progn (if selection
(dolist (section selection)
(magit-diff-highlight-list section selection))
(magit-diff-highlight-list section))
t)
(when-let ((scope (magit-diff-scope section t)))
(cond ((eq scope 'region)
(magit-diff-paint-hunk section selection t))
(selection
(dolist (section selection)
(magit-diff-highlight-recursive section selection)))
(t
(magit-diff-highlight-recursive section)))
t)))
(defun magit-diff-highlight-recursive (section &optional selection)
(pcase (magit-diff-scope section)
('list (magit-diff-highlight-list section selection))
('file (magit-diff-highlight-file section selection))
('hunk (magit-diff-highlight-heading section selection)
(magit-diff-paint-hunk section selection t))
(_ (magit-section-highlight section nil))))
(defun magit-diff-highlight-list (section &optional selection)
(if (oref section children)
(let ((beg (oref section start))
(cnt (oref section content))
(end (oref section end)))
(when (or (eq this-command #'mouse-drag-region)
(not selection))
(unless (and (region-active-p)
(<= (region-beginning) beg))
(magit-section-make-overlay beg cnt 'magit-section-highlight))
(if (oref section hidden)
(oset section washer #'ignore)
(dolist (child (oref section children))
(when (or (eq this-command #'mouse-drag-region)
(not (and (region-active-p)
(<= (region-beginning)
(oref child start)))))
(magit-diff-highlight-recursive child selection)))))
(when magit-diff-highlight-hunk-body
(magit-section-make-overlay (1- end) end 'magit-section-highlight)))
(magit-section-highlight section nil)))
(defun magit-diff-highlight-file (section &optional selection)
(magit-diff-highlight-heading section selection)
(when (or (not (oref section hidden))
(cl-typep section 'magit-module-section))
(dolist (child (oref section children))
(magit-diff-highlight-recursive child selection))))
(defun magit-diff-highlight-heading (section &optional selection)
(magit-section-make-overlay
(oref section start)
(or (oref section content)
(oref section end))
(pcase (list (oref section type)
(and (member section selection)
(not (eq this-command #'mouse-drag-region))))
('(file t) 'magit-diff-file-heading-selection)
('(file nil) 'magit-diff-file-heading-highlight)
('(module t) 'magit-diff-file-heading-selection)
('(module nil) 'magit-diff-file-heading-highlight)
('(hunk t) 'magit-diff-hunk-heading-selection)
('(hunk nil) 'magit-diff-hunk-heading-highlight))))
;;; Hunk Paint
(cl-defun magit-diff-paint-hunk
(section &optional selection
(highlight (magit-section-selected-p section selection)))
(let (paint)
(unless magit-diff-highlight-hunk-body
(setq highlight nil))
(cond (highlight
(unless (oref section hidden)
(cl-pushnew section magit-section-highlighted-sections)
(cond ((memq section magit-section-unhighlight-sections)
(setq magit-section-unhighlight-sections
(delq section magit-section-unhighlight-sections)))
(magit-diff-highlight-hunk-body
(setq paint t)))))
(t
(cond ((and (oref section hidden)
(memq section magit-section-unhighlight-sections))
(cl-pushnew section magit-section-highlighted-sections)
(setq magit-section-unhighlight-sections
(delq section magit-section-unhighlight-sections)))
(t
(setq paint t)))))
(when paint
(save-excursion
(goto-char (oref section start))
(let ((end (oref section end))
(merging (looking-at "@@@"))
(diff-type (magit-diff-type))
(stage nil)
(tab-width (magit-diff-tab-width
(magit-section-parent-value section))))
(forward-line)
(while (< (point) end)
(when (and magit-diff-hide-trailing-cr-characters
(char-equal ?\r (char-before (line-end-position))))
(put-text-property (1- (line-end-position)) (line-end-position)
'invisible t))
(put-text-property
(point) (1+ (line-end-position)) 'font-lock-face
(cond
((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}")
(setq stage (pcase (list (match-string 1) highlight)
('("<" nil) 'magit-diff-our)
('("<" t) 'magit-diff-our-highlight)
('("|" nil) 'magit-diff-base)
('("|" t) 'magit-diff-base-highlight)
('("=" nil) 'magit-diff-their)
('("=" t) 'magit-diff-their-highlight)
('(">" nil) nil)))
'magit-diff-conflict-heading)
((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+"))
(magit-diff-paint-tab merging tab-width)
(magit-diff-paint-whitespace merging 'added diff-type)
(or stage
(if highlight 'magit-diff-added-highlight 'magit-diff-added)))
((looking-at (if merging "^\\(-\\| -\\)" "^-"))
(magit-diff-paint-tab merging tab-width)
(magit-diff-paint-whitespace merging 'removed diff-type)
(if highlight 'magit-diff-removed-highlight 'magit-diff-removed))
(t
(magit-diff-paint-tab merging tab-width)
(magit-diff-paint-whitespace merging 'context diff-type)
(if highlight 'magit-diff-context-highlight 'magit-diff-context))))
(forward-line))))))
(magit-diff-update-hunk-refinement section))
(cl-defmethod magit-section-paint ((section magit-hunk-section) highlight)
(unless magit-diff-highlight-hunk-body
(setq highlight nil))
(let ((end (oref section end))
(merging (looking-at "@@@"))
(diff-type (magit-diff-type))
(stage nil)
(tab-width (magit-diff-tab-width
(magit-section-parent-value section))))
(forward-line)
(while (< (point) end)
(when (and magit-diff-hide-trailing-cr-characters
(char-equal ?\r (char-before (line-end-position))))
(put-text-property (1- (line-end-position)) (line-end-position)
'invisible t))
(put-text-property
(point) (1+ (line-end-position)) 'font-lock-face
(cond
((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}")
(setq stage (pcase (list (match-string 1) highlight)
('("<" nil) 'magit-diff-our)
('("<" t) 'magit-diff-our-highlight)
('("|" nil) 'magit-diff-base)
('("|" t) 'magit-diff-base-highlight)
('("=" nil) 'magit-diff-their)
('("=" t) 'magit-diff-their-highlight)
('(">" nil) nil)))
'magit-diff-conflict-heading)
((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+"))
(magit-diff-paint-tab merging tab-width)
(magit-diff-paint-whitespace merging 'added diff-type)
(or stage
(if highlight 'magit-diff-added-highlight 'magit-diff-added)))
((looking-at (if merging "^\\(-\\| -\\)" "^-"))
(magit-diff-paint-tab merging tab-width)
(magit-diff-paint-whitespace merging 'removed diff-type)
(if highlight 'magit-diff-removed-highlight 'magit-diff-removed))
(t
(magit-diff-paint-tab merging tab-width)
(magit-diff-paint-whitespace merging 'context diff-type)
(if highlight 'magit-diff-context-highlight 'magit-diff-context))))
(forward-line)))
(when (eq magit-diff-refine-hunk 'all)
(magit-diff-update-hunk-refinement section))
(oset section painted (if highlight 'highlight 'plain)))
(defvar magit-diff--tab-width-cache nil)
@@ -3490,7 +3395,11 @@ are highlighted."
(overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning)
(overlay-put ov 'priority 2)
(overlay-put ov 'evaporate t))))))
(cl-defmethod magit-section--refine ((section magit-hunk-section))
(when (eq magit-diff-refine-hunk t)
(magit-diff-update-hunk-refinement section)))
(defun magit-diff-update-hunk-refinement (&optional section allow-remove)
(if section
(unless (oref section hidden)
@@ -3504,22 +3413,22 @@ are highlighted."
;; `diff-refine-hunk' does not handle combined diffs.
(unless (looking-at "@@@")
(let ((smerge-refine-ignore-whitespace
magit-diff-refine-ignore-whitespace)
magit-diff-refine-ignore-whitespace)
;; Avoid fsyncing many small temp files.
(write-region-inhibit-fsync t))
(diff-refine-hunk)))))
(diff-refine-hunk)))))
((and (guard allow-remove)
(or `(nil t ,_) '(t t nil)))
(oset section refined nil)
(remove-overlays (oref section start)
(oref section end)
'diff-mode 'fine))))
(cl-labels ((recurse (section)
(if (magit-section-match 'hunk section)
(if (magit-section-match 'hunk section)
(magit-diff-update-hunk-refinement section t)
(dolist (child (oref section children))
(recurse child)))))
(recurse magit-root-section))))
;;; Hunk Region

109
lisp/magit/magit-dired.el Normal file
View File

@@ -0,0 +1,109 @@
;;; magit-dired.el --- Dired support for Magit -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; SPDX-License-Identifier: GPL-3.0-or-later
;; Magit 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.
;;
;; Magit 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 Magit. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Dired support for Magit.
;;; Code:
(require 'magit)
;; For `magit-do-async-shell-command'.
(declare-function dired-read-shell-command "dired-aux" (prompt arg files))
;;; Open Dired from Magit
;;;###autoload
(defun magit-dired-jump (&optional other-window)
"Visit file at point using Dired.
With a prefix argument, visit in another window. If there
is no file at point, then instead visit `default-directory'."
(interactive "P")
(dired-jump other-window
(and-let* ((file (magit-file-at-point)))
(expand-file-name (if (file-directory-p file)
(file-name-as-directory file)
file)))))
;;; Commands for Dired Buffers
;;;###autoload
(defun magit-dired-stage ()
"In Dired, staged all marked files or the file at point."
(interactive)
(magit-stage-files (dired-get-marked-files)))
;;;###autoload
(defun magit-dired-unstage ()
"In Dired, unstaged all marked files or the file at point."
(interactive)
(magit-unstage-files (dired-get-marked-files)))
;;;###autoload
(defun magit-dired-log (&optional follow)
"In Dired, show log for all marked files or the directory if none are marked."
(interactive "P")
(if-let ((topdir (magit-toplevel default-directory)))
(let ((args (car (magit-log-arguments)))
(files (or (dired-get-marked-files nil 'marked)
(list default-directory))))
(when (and follow
(not (member "--follow" args))
(not (cdr files)))
(push "--follow" args))
(magit-log-setup-buffer
(list (or (magit-get-current-branch) "HEAD"))
args
(let ((default-directory topdir))
(mapcar #'file-relative-name files))
magit-log-buffer-file-locked))
(magit--not-inside-repository-error)))
;;;###autoload
(defun magit-dired-am-apply-patches (repo &optional arg)
"In Dired, apply the marked (or next ARG) files as patches.
If inside a repository, then apply in that. Otherwise prompt
for a repository."
(interactive (list (or (magit-toplevel)
(magit-read-repository t))
current-prefix-arg))
(let ((files (dired-get-marked-files nil arg nil nil t)))
(magit-status-setup-buffer repo)
(magit-am-apply-patches files)))
;;; Miscellaneous Commands
;;;###autoload
(defun magit-do-async-shell-command (file)
"Open FILE with `dired-do-async-shell-command'.
Interactively, open the file at point."
(interactive (list (or (magit-file-at-point)
(magit-read-file "Act on file"))))
(require 'dired-aux)
(dired-do-async-shell-command
(dired-read-shell-command "& on %s: " current-prefix-arg (list file))
nil (list file)))
;;; _
(provide 'magit-dired)
;;; magit-dired.el ends here

View File

@@ -224,8 +224,7 @@ and alternative commands."
(let* ((dir (magit-gitdir))
(revA (or (magit-name-branch "HEAD")
(magit-commit-p "HEAD")))
(revB (cl-find-if (lambda (head)
(file-exists-p (expand-file-name head dir)))
(revB (cl-find-if (##file-exists-p (expand-file-name % dir))
'("MERGE_HEAD" "CHERRY_PICK_HEAD" "REVERT_HEAD")))
(revB (or (magit-name-branch revB)
(magit-commit-p revB)))
@@ -266,7 +265,7 @@ and alternative commands."
(save-excursion
(goto-char (point-min))
(unless (re-search-forward "^<<<<<<< " nil t)
(magit-stage-file file))))))))
(magit-stage-files (list file)))))))))
(if fileC
(magit-ediff-buffers
((magit-get-revision-buffer revA fileA)

View File

@@ -28,14 +28,10 @@
(require 'magit)
;; For `magit-do-async-shell-command'.
(declare-function dired-read-shell-command "dired-aux" (prompt arg files))
;; For `magit-project-status'.
(declare-function vc-git-command "vc-git"
(buffer okstatus file-or-list &rest flags))
(defvar ido-exit)
(defvar ido-fallback)
(defvar project-prefix-map)
(defvar project-switch-commands)
@@ -193,19 +189,6 @@ blame to center around the line point is on."
;;; Emacs Tools
;;;###autoload
(defun ido-enter-magit-status ()
"Drop into `magit-status' from file switching.
To make this command available use something like:
(keymap-set ido-common-completion-map
\"C-x g\" \\='ido-enter-magit-status)"
(interactive)
(setq ido-exit 'fallback)
(setq ido-fallback #'magit-status)
(exit-minibuffer))
;;;###autoload
(defun magit-project-status ()
"Run `magit-status' in the current project's root."
@@ -232,62 +215,6 @@ to nil before loading Magit to prevent \"m\" from being bound.")
(keymap-set project-prefix-map "m" #'magit-project-status)
(add-to-list 'project-switch-commands '(magit-project-status "Magit") t)))
;;;###autoload
(defun magit-dired-jump (&optional other-window)
"Visit file at point using Dired.
With a prefix argument, visit in another window. If there
is no file at point, then instead visit `default-directory'."
(interactive "P")
(dired-jump other-window
(and-let* ((file (magit-file-at-point)))
(expand-file-name (if (file-directory-p file)
(file-name-as-directory file)
file)))))
;;;###autoload
(defun magit-dired-log (&optional follow)
"Show log for all marked files, or the current file."
(interactive "P")
(if-let ((topdir (magit-toplevel default-directory)))
(let ((args (car (magit-log-arguments)))
(files (dired-get-marked-files nil nil #'magit-file-tracked-p)))
(unless files
(user-error "No marked file is being tracked by Git"))
(when (and follow
(not (member "--follow" args))
(not (cdr files)))
(push "--follow" args))
(magit-log-setup-buffer
(list (or (magit-get-current-branch) "HEAD"))
args
(let ((default-directory topdir))
(mapcar #'file-relative-name files))
magit-log-buffer-file-locked))
(magit--not-inside-repository-error)))
;;;###autoload
(defun magit-dired-am-apply-patches (repo &optional arg)
"In Dired, apply the marked (or next ARG) files as patches.
If inside a repository, then apply in that. Otherwise prompt
for a repository."
(interactive (list (or (magit-toplevel)
(magit-read-repository t))
current-prefix-arg))
(let ((files (dired-get-marked-files nil arg nil nil t)))
(magit-status-setup-buffer repo)
(magit-am-apply-patches files)))
;;;###autoload
(defun magit-do-async-shell-command (file)
"Open FILE with `dired-do-async-shell-command'.
Interactively, open the file at point."
(interactive (list (or (magit-file-at-point)
(magit-read-file "Act on file"))))
(require 'dired-aux)
(dired-do-async-shell-command
(dired-read-shell-command "& on %s: " current-prefix-arg (list file))
nil (list file)))
;;; Shift Selection
(defun magit--turn-on-shift-select-mode-p ()

View File

@@ -99,8 +99,8 @@ Otherwise if a remote named \"origin\" exists, then use that.
If no remote can be determined, then this command is not available
from the `magit-fetch' transient prefix and invoking it directly
results in an error."
:if (lambda () (magit-get-current-remote t))
:description (lambda () (magit-get-current-remote t))
:if (##magit-get-current-remote t)
:description (##magit-get-current-remote t)
(interactive (list (magit-get-current-remote t)
(magit-fetch-arguments)))
(unless remote

View File

@@ -300,8 +300,10 @@ to `magit-dispatch'."
:info-manual "(magit) Minor Mode for Buffers Visiting Files"
[:if magit-file-relative-name
["File actions"
(" s" "Stage" magit-stage-buffer-file)
(" u" "Unstage" magit-unstage-buffer-file)
(" s" "Stage" magit-file-stage :if-not-derived dired-mode)
(" s" "Stage" magit-dired-stage :if-derived dired-mode)
(" u" "Unstage" magit-file-unstage :if-not-derived dired-mode)
(" u" "Unstage" magit-dired-unstage :if-derived dired-mode)
(", x" "Untrack" magit-file-untrack)
(", r" "Rename" magit-file-rename)
(", k" "Delete" magit-file-delete)
@@ -311,9 +313,10 @@ to `magit-dispatch'."
("d" "Diff" magit-diff-buffer-file)]
[""
("L" "Log..." magit-log)
("l" "Log" magit-log-buffer-file)
("l" "Log" magit-log-buffer-file :if-not-derived dired-mode)
("l" "Log" magit-dired-log :if-derived dired-mode)
("t" "Trace" magit-log-trace-definition)
(7 "M" "Merged" magit-log-merged)]
("M" "Merged" magit-log-merged :level 7)]
[""
("B" "Blame..." magit-blame)
("b" "Blame" magit-blame-addition)
@@ -333,8 +336,8 @@ to `magit-dispatch'."
("e" "Edit line" magit-edit-line-commit)]]
[:if-not magit-file-relative-name
["File actions"
("s" "Stage" magit-stage-file)
("u" "Unstage" magit-unstage-file)
("s" "Stage" magit-stage-files)
("u" "Unstage" magit-unstage-files)
("x" "Untrack" magit-file-untrack)
("r" "Rename" magit-file-rename)
("k" "Delete" magit-file-delete)
@@ -419,6 +422,44 @@ the same location in the respective file in the working tree."
;;; File Commands
;;;###autoload
(defun magit-file-stage ()
"Stage all changes to the file being visited in the current buffer."
(interactive)
(unless buffer-file-name
(user-error "Not visiting a file"))
(magit-with-toplevel
(magit-stage-1 (and (magit-file-ignored-p buffer-file-name)
(if (y-or-n-p "Visited file is ignored; stage anyway?")
"--force"
(user-error "Abort")))
(list (magit-file-relative-name)))))
;;;###autoload
(defun magit-file-unstage ()
"Unstage all changes to the file being visited in the current buffer."
(interactive)
(unless buffer-file-name
(user-error "Not visiting a file"))
(magit-with-toplevel
(magit-unstage-1 (list (magit-file-relative-name)))))
;;;###autoload
(defun magit-file-untrack (files &optional force)
"Untrack the selected FILES or one file read in the minibuffer.
With a prefix argument FORCE do so even when the files have
staged as well as unstaged changes."
(interactive (list (or (if-let ((files (magit-region-values 'file t)))
(if (magit-file-tracked-p (car files))
(magit-confirm-files 'untrack files "Untrack")
(user-error "Already untracked"))
(list (magit-read-tracked-file "Untrack file"))))
current-prefix-arg))
(magit-with-toplevel
(magit-run-git "rm" "--cached" (and force "--force") "--" files)))
;;;###autoload
(defun magit-file-rename (file newname)
"Rename or move FILE to NEWNAME.
NEWNAME may be a file or directory name. If FILE isn't tracked in
@@ -455,20 +496,7 @@ Git, fallback to using `rename-file'."
(vc-find-file-hook))))))
(magit-refresh))
(defun magit-file-untrack (files &optional force)
"Untrack the selected FILES or one file read in the minibuffer.
With a prefix argument FORCE do so even when the files have
staged as well as unstaged changes."
(interactive (list (or (if-let ((files (magit-region-values 'file t)))
(if (magit-file-tracked-p (car files))
(magit-confirm-files 'untrack files "Untrack")
(user-error "Already untracked"))
(list (magit-read-tracked-file "Untrack file"))))
current-prefix-arg))
(magit-with-toplevel
(magit-run-git "rm" "--cached" (and force "--force") "--" files)))
;;;###autoload
(defun magit-file-delete (files &optional force)
"Delete the selected FILES or one file read in the minibuffer.
@@ -556,5 +584,12 @@ If DEFAULT is non-nil, use this as the default value instead of
(concat "No file changed in " rev-or-range)))
;;; _
(define-obsolete-function-alias 'magit-stage-buffer-file
'magit-file-stage "Magit 4.3.2")
(define-obsolete-function-alias 'magit-unstage-buffer-file
'magit-file-unstage "Magit 4.3.2")
(provide 'magit-files)
;;; magit-files.el ends here

View File

@@ -150,6 +150,7 @@ option."
"-c" "log.showSignature=false"
"-c" "color.ui=false"
"-c" "color.diff=false"
"-c" "diff.noPrefix=false"
,@(and (eq system-type 'windows-nt)
(list "-c" "i18n.logOutputEncoding=UTF-8")))
"Global Git arguments.
@@ -165,7 +166,7 @@ anything that is part of the default value, unless you really
know what you are doing. And think very hard before adding
something; it will be used every time Magit runs Git for any
purpose."
:package-version '(magit . "2.9.0")
:package-version '(magit . "4.3.2")
:group 'magit-commands
:group 'magit-process
:type '(repeat string))
@@ -225,7 +226,16 @@ framework ultimately determines how the collection is displayed."
;;; Git
(defvar magit-git-debug nil)
(defvar magit-git-debug nil
"Whether and how to enable additional debugging of git errors.
Use `magit-toggle-git-debug' (which see) to toggle the boolean value of
this variable. This can also manually be set to `include-success', in
which case successful git invocations are also logged.
This can also be a function, which takes one argument, the error output
as a string. This is intended for internal use and is established using
let-bindings around critical code (i.e., in `magit--assert-usable-git').")
(defun magit-toggle-git-debug ()
"Toggle whether additional git errors are reported.
@@ -234,7 +244,8 @@ Magit basically calls git for one of these two reasons: for
side-effects or to do something with its standard output.
When git is run for side-effects then its output, including error
messages, go into the process buffer which is shown when using ~$~.
messages, go into the process buffer which is shown when using \
\\<magit-mode-map>\\[magit-process-buffer].
When git's output is consumed in some way, then it would be too
expensive to also insert it into this buffer, but with this command
@@ -452,7 +463,7 @@ a boolean, then raise an error."
(defun magit-git-insert (&rest args)
"Execute Git with ARGS, insert stdout at point and return exit code.
If `magit-git-debug' in non-nil and the exit code is non-zero, then
If `magit-git-debug' is non-nil and the exit code is non-zero, then
insert the run command and stderr into the process buffer."
(apply #'magit--git-insert nil args))
@@ -465,7 +476,7 @@ insert the run command and stderr into the process buffer."
(setq log (make-temp-file "magit-stderr"))
(delete-file log)
(setq exit (magit-process-git (list t log) args))
(when (or (> exit 0) (eq magit-git-debug 'all))
(when (or (> exit 0) (eq magit-git-debug 'include-success))
(when (file-exists-p log)
(with-temp-buffer
(insert-file-contents log)
@@ -473,7 +484,8 @@ insert the run command and stderr into the process buffer."
(setq errmsg
(cond
((eq return-error 'full)
(buffer-string))
(let ((str (buffer-string)))
(and (not (equal str "")) str)))
((functionp magit-git-debug)
(funcall magit-git-debug (buffer-string)))
((magit--locate-error-message)))))
@@ -497,7 +509,7 @@ insert the run command and stderr into the process buffer."
(defun magit--locate-error-message ()
(goto-char (point-max))
(and (run-hook-wrapped 'magit-process-error-message-regexps
(lambda (re) (re-search-backward re nil t)))
(##re-search-backward % nil t))
(match-string-no-properties 1)))
(defun magit-git-string (&rest args)
@@ -516,8 +528,8 @@ newline, return an empty string."
"Execute Git with ARGS, returning its output as a list of lines.
Empty lines anywhere in the output are omitted.
If Git exits with a non-zero exit status, then report show a
message and add a section in the respective process buffer."
If Git exits with a non-zero exit status, show a message and add
a section in the respective process buffer."
(magit--with-temp-process-buffer
(apply #'magit-git-insert args)
(split-string (buffer-string) "\n" t)))
@@ -526,24 +538,32 @@ message and add a section in the respective process buffer."
"Execute Git with ARGS, returning its null-separated output as a list.
Empty items anywhere in the output are omitted.
If Git exits with a non-zero exit status, then report show a
message and add a section in the respective process buffer."
If Git exits with a non-zero exit status, show a message and add
a section in the respective process buffer."
(magit--with-temp-process-buffer
(apply #'magit-git-insert args)
(split-string (buffer-string) "\0" t)))
(defvar magit--git-wash-keep-error t)
(defun magit-git-wash (washer &rest args)
"Execute Git with ARGS, inserting washed output at point.
Actually first insert the raw output at point. If there is no
output, call `magit-cancel-section'. Otherwise temporarily narrow
the buffer to the inserted text, move to its beginning, and then
call function WASHER with ARGS as its sole argument."
"Execute git with ARGS, inserting washed output at point.
First insert the raw output at point. If there is no output, call
`magit-cancel-section'. Otherwise temporarily narrow the buffer to
the inserted text, move to its beginning, and finally call function
WASHER with ARGS as its sole argument.
If git exits with a non-zero exit status, apply the `error' face to
the error message, instead of calling WASHER. To instead cancel the
section use `magit--git-wash'."
(declare (indent 1))
(apply #'magit--git-wash washer magit--git-wash-keep-error args))
(apply #'magit--git-wash washer t args))
(defun magit--git-wash (washer keep-error &rest args)
"Execute git with ARGS, inserting washed output at point.
Like `magit-git-wash' but if KEEP-ERROR is nil and an error occurs, also
insert standard error. If KEEP-ERROR is `wash-anyway', insert and wash
standard output even in case of an error."
(declare (indent 2))
(setq args (flatten-tree args))
(let ((beg (point))
@@ -678,7 +698,7 @@ values of `magit-remote-git-executable' and `exec-path'.\n"))
Also include information about `magit-remote-git-executable'.
See info node `(magit)Debugging Tools' for more information."
(interactive)
(with-current-buffer (get-buffer-create "*magit-git-debug*")
(with-current-buffer (get-buffer-create "*magit-git-executable*")
(pop-to-buffer (current-buffer))
(erase-buffer)
(insert (format "magit-remote-git-executable: %S\n"
@@ -794,7 +814,7 @@ Also see `magit-git-config-p'."
(defun magit-git-dir (&optional path)
"Like (expand-file-name PATH (magit-gitdir)) or just (magit-gitdir)."
(declare (obsolete 'magit-gitdir "Magit 4.0.0"))
(declare (obsolete magit-gitdir "Magit 4.0.0"))
(and-let* ((dir (magit-gitdir)))
(if path
(expand-file-name (convert-standard-filename path) dir)
@@ -1181,7 +1201,7 @@ Sorted from longest to shortest CYGWIN name."
(setq filename (expand-file-name filename)))
(if-let ((cyg:win (and (not (file-remote-p default-directory)) ; see #4976
(cl-assoc filename magit-cygwin-mount-points
:test (lambda (f cyg) (string-prefix-p cyg f))))))
:test (##string-prefix-p %2 %1)))))
(concat (cdr cyg:win)
(substring filename (length (car cyg:win))))
filename))
@@ -1195,7 +1215,7 @@ Sorted from longest to shortest CYGWIN name."
3. Deal with an `windows-nt' Emacs vs. Cygwin Git incompatibility."
(if (file-name-absolute-p filename)
(if-let ((cyg:win (cl-rassoc filename magit-cygwin-mount-points
:test (lambda (f win) (string-prefix-p win f)))))
:test (##string-prefix-p %2 %1))))
(concat (car cyg:win)
(substring filename (length (cdr cyg:win))))
(let ((expanded (expand-file-name filename)))
@@ -1285,8 +1305,7 @@ are considered."
(not (magit-module-worktree-p module)))
(defun magit-ignore-submodules-p (&optional return-argument)
(or (cl-find-if (lambda (arg)
(string-prefix-p "--ignore-submodules" arg))
(or (cl-find-if (##string-prefix-p "--ignore-submodules" %)
magit-buffer-diff-args)
(and-let* ((value (magit-get "diff.ignoreSubmodules")))
(if return-argument
@@ -1508,6 +1527,7 @@ to, or to some other symbolic-ref that points to the same ref."
(pullreq (and (fboundp 'forge--pullreq-branch)
(magit-branch-p
(forge--pullreq-branch (oref it value)))))
(related-refs (magit--painted-branch-at-point))
((unpulled unpushed)
(magit-ref-abbrev
(replace-regexp-in-string "\\.\\.\\.?" "" (oref it value))))))
@@ -1629,7 +1649,7 @@ The amount of time spent searching is limited by
(defun magit--set-default-branch (newname oldname)
(let ((remote (or (magit-primary-remote)
(user-error "Cannot determine primary remote")))
(branches (mapcar (lambda (line) (split-string line "\t"))
(branches (mapcar (##split-string % "\t")
(magit-git-lines
"for-each-ref" "refs/heads"
"--format=%(refname:short)\t%(upstream:short)"))))
@@ -1697,6 +1717,11 @@ according to the branch type."
'magit-branch-local
'magit-branch-remote)))))
(defun magit-get-local-upstream-branch (&optional branch)
(and-let* ((upstream (magit-get-upstream-branch branch))
(upstream (cdr (magit-split-branch-name upstream))))
(and (magit-branch-p upstream) upstream)))
(defun magit-get-indirect-upstream-branch (branch &optional force)
(let ((remote (magit-get "branch" branch "remote")))
(and remote (not (equal remote "."))
@@ -1807,8 +1832,7 @@ exists, then remotes in `magit-primary-remote-names' are tried in
order and the first remote from that list that actually exists in
the current repository is considered its primary remote."
(let ((remotes (magit-list-remotes)))
(seq-find (lambda (name)
(member name remotes))
(seq-find (##member % remotes)
(delete-dups
(delq nil
(cons (magit-get "magit.primaryRemote")
@@ -1982,8 +2006,7 @@ SORTBY is a key or list of keys to pass to the `--sort' flag of
(defun magit-list-special-refnames ()
(let ((gitdir (magit-gitdir)))
(cl-remove-if-not (lambda (name)
(file-exists-p (expand-file-name name gitdir)))
(cl-remove-if-not (##file-exists-p (expand-file-name % gitdir))
magit-special-refnames)))
(defun magit-list-branch-names ()
@@ -2043,9 +2066,8 @@ SORTBY is a key or list of keys to pass to the `--sort' flag of
(defun magit-remote-head (remote)
(and-let* ((line (cl-find-if
(lambda (line)
(string-match
"\\`ref: refs/heads/\\([^\s\t]+\\)[\s\t]HEAD\\'" line))
(##string-match
"\\`ref: refs/heads/\\([^\s\t]+\\)[\s\t]HEAD\\'" %)
(magit-git-lines "ls-remote" "--symref" remote "HEAD"))))
(match-string 1 line)))
@@ -2182,8 +2204,7 @@ exists, then the branch names in `magit-main-branch-names' are
tried in order. The first branch from that list that actually
exists in the current repository is considered its main branch."
(let ((branches (magit-list-local-branch-names)))
(seq-find (lambda (name)
(member name branches))
(seq-find (##member % branches)
(delete-dups
(delq nil
(cons (magit-get "init.defaultBranch")

View File

@@ -42,10 +42,9 @@
("p" "privately (.git/info/exclude)"
magit-gitignore-in-gitdir)
("g" magit-gitignore-on-system
:if (lambda () (magit-get "core.excludesfile"))
:description (lambda ()
(format "privately for all repositories (%s)"
(magit-get "core.excludesfile"))))]
:if (##magit-get "core.excludesfile")
:description (##format "privately for all repositories (%s)"
(magit-get "core.excludesfile")))]
["Skip worktree"
(7 "w" "do skip worktree" magit-skip-worktree)
(7 "W" "do not skip worktree" magit-no-skip-worktree)]

View File

@@ -31,6 +31,7 @@
(require 'magit-core)
(require 'magit-diff)
(declare-function magit--any-wip-mode-enabled-p "magit-wip" ())
(declare-function magit-blob-visit "magit-files" (blob-or-file))
(declare-function magit-cherry-apply "magit-sequence" (commit &optional args))
(declare-function magit-insert-head-branch-header "magit-status"
@@ -77,7 +78,7 @@
:group 'magit-log
:type 'hook)
(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L")
(defcustom magit-log-remove-graph-args '("--follow" "-G" "-S" "-L")
"The log arguments that cause the `--graph' argument to be dropped.
The default value lists the arguments that are incompatible with
@@ -86,10 +87,10 @@ can add additional arguments that are available in `magit-log',
but I recommend that you don't do that. Nowadays I would define
this as a constant, but I am preserving it as an option, in case
someone actually customized it."
:package-version '(magit . "2.3.0")
:package-version '(magit . "4.3.7")
:group 'magit-log
:type '(repeat (string :tag "Argument"))
:options '("--follow" "--grep" "-G" "-S" "-L"))
:options '("--follow" "-G" "-S" "-L"))
(defcustom magit-log-revision-headers-format "\
%+b%+N
@@ -173,9 +174,9 @@ want to use the same functions for both hooks."
"Function used to generate text shown in header line of log buffers."
:package-version '(magit . "2.12.0")
:group 'magit-log
:type `(choice (function-item ,#'magit-log-header-line-arguments)
(function-item ,#'magit-log-header-line-sentence)
function))
:type `(radio (function-item ,#'magit-log-header-line-arguments)
(function-item ,#'magit-log-header-line-sentence)
function))
(defcustom magit-log-trace-definition-function #'magit-which-function
"Function used to determine the function at point.
@@ -184,10 +185,10 @@ You should prefer `magit-which-function' over `which-function'
because the latter may make use of Imenu's outdated cache."
:package-version '(magit . "3.0.0")
:group 'magit-log
:type `(choice (function-item ,#'magit-which-function)
(function-item ,#'which-function)
(function-item ,#'add-log-current-defun)
function))
:type `(radio (function-item ,#'magit-which-function)
(function-item ,#'which-function)
(function-item ,#'add-log-current-defun)
function))
(defcustom magit-log-color-graph-limit 256
"Number of commits over which log graphs are not colored.
@@ -442,89 +443,92 @@ commits before and half after."
;;; Commands
;;;; Prefix Commands
(eval-and-compile
(defvar magit-log-infix-arguments
;; The grouping in git-log(1) appears to be guided by implementation
;; details, so our logical grouping only follows it to an extend.
;; Arguments that are "misplaced" here:
;; 1. From "Commit Formatting".
;; 2. From "Common Diff Options".
;; 3. From unnamed first group.
;; 4. Implemented by Magit.
[:class transient-subgroups
["Commit limiting"
(magit-log:-n)
(magit:--author)
(7 magit-log:--since)
(7 magit-log:--until)
(magit-log:--grep)
(7 "-i" "Search case-insensitive" ("-i" "--regexp-ignore-case"))
(7 "-I" "Invert search pattern" "--invert-grep")
(magit-log:-G) ;2
(magit-log:-S) ;2
(magit-log:-L) ;2
(7 "=m" "Omit merges" "--no-merges")
(7 "=p" "First parent" "--first-parent")]
["History simplification"
( "-D" "Simplify by decoration" "--simplify-by-decoration")
(magit:--)
( "-f" "Follow renames when showing single-file log" "--follow") ;3
(6 "/s" "Only commits changing given paths" "--sparse")
(7 "/d" "Only selected commits plus meaningful history" "--dense")
(7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path")
(6 "/f" "Do not prune history" "--full-history")
(7 "/m" "Prune some history" "--simplify-merges")]
["Commit ordering"
(magit-log:--*-order)
("-r" "Reverse order" "--reverse")]
["Formatting"
("-g" "Show graph" "--graph") ;1
("-c" "Show graph in color" "--color") ;2
("-d" "Show refnames" "--decorate") ;3
("=S" "Show signatures" "--show-signature") ;1
("-h" "Show header" "++header") ;4
("-p" "Show diffs" ("-p" "--patch")) ;2
("-s" "Show diffstats" "--stat")] ;2
]))
(transient-define-group magit-log-infix-arguments
;; The grouping in git-log(1) appears to be guided by implementation
;; details, so our logical grouping only follows it to an extend.
;; Arguments that are "misplaced" here:
;; 1. From "Commit Formatting".
;; 2. From "Common Diff Options".
;; 3. From unnamed first group.
;; 4. Implemented by Magit.
["Commit limiting"
:if magit-log-infix-arguments--show-p
(magit-log:-n)
(magit:--author)
(7 magit-log:--since)
(7 magit-log:--until)
(magit-log:--grep)
(7 "-i" "Search case-insensitive" ("-i" "--regexp-ignore-case"))
(7 "-I" "Invert search pattern" "--invert-grep")
(magit-log:-G) ;2
(magit-log:-S) ;2
(magit-log:-L) ;2
(7 "=m" "Omit merges" "--no-merges")
(7 "=p" "First parent" "--first-parent")]
["History simplification"
:if magit-log-infix-arguments--show-p
( "-D" "Simplify by decoration" "--simplify-by-decoration")
(magit:--)
( "-f" "Follow renames when showing single-file log" "--follow") ;3
(6 "/s" "Only commits changing given paths" "--sparse")
(7 "/d" "Only selected commits plus meaningful history" "--dense")
(7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path")
(6 "/f" "Do not prune history" "--full-history")
(7 "/m" "Prune some history" "--simplify-merges")]
["Commit ordering"
:if magit-log-infix-arguments--show-p
(magit-log:--*-order)
("-r" "Reverse order" "--reverse")]
["Formatting"
:if magit-log-infix-arguments--show-p
("-g" "Show graph" "--graph") ;1
("-c" "Show graph in color" "--color") ;2
("-d" "Show refnames" "--decorate") ;3
("=S" "Show signatures" "--show-signature") ;1
("-h" "Show header" "++header") ;4
("-p" "Show diffs" ("-p" "--patch")) ;2
("-s" "Show diffstats" "--stat")]) ;2
(defun magit-log-infix-arguments--show-p ()
(if (eq (oref (transient-prefix-object) command) 'magit-log-refresh)
(eq major-mode 'magit-log-mode)
t))
;;;###autoload (autoload 'magit-log "magit-log" nil t)
(transient-define-prefix magit-log ()
"Show a commit or reference log."
:man-page "git-log"
:class 'magit-log-prefix
[magit-log-infix-arguments]
'magit-log-infix-arguments
[["Log"
("l" "current" magit-log-current)
("h" "HEAD" magit-log-head)
("u" "related" magit-log-related)
("o" "other" magit-log-other)]
("l" magit-log-current)
("o" "other" magit-log-other)
("h" "HEAD" magit-log-head :level 0)
("u" "related" magit-log-related)]
[""
("L" "local branches" magit-log-branches)
("b" "all branches" magit-log-all-branches)
("a" "all references" magit-log-all)
(7 "B" "matching branches" magit-log-matching-branches)
(7 "T" "matching tags" magit-log-matching-tags)
(7 "m" "merged" magit-log-merged)]
("L" "local branches" magit-log-branches)
("b" "all branches" magit-log-all-branches)
("a" "all references" magit-log-all)
("B" "matching branches" magit-log-matching-branches :level 7)
("T" "matching tags" magit-log-matching-tags :level 7)
("m" "merged" magit-log-merged :level 7)]
["Reflog"
("r" "current" magit-reflog-current)
("H" "HEAD" magit-reflog-head)
("O" "other" magit-reflog-other)]
[:if (lambda ()
(and (fboundp 'magit--any-wip-mode-enabled-p)
(magit--any-wip-mode-enabled-p)))
("r" "current" magit-reflog-current)
("O" "other" magit-reflog-other)
("H" "HEAD" magit-reflog-head)]
[:if magit--any-wip-mode-enabled-p
:description "Wiplog"
("i" "index" magit-wip-log-index)
("w" "worktree" magit-wip-log-worktree)]
("i" "index" magit-wip-log-index)
("w" "worktree" magit-wip-log-worktree)]
["Other"
(5 "s" "shortlog" magit-shortlog)]])
("s" "shortlog" magit-shortlog)]])
;;;###autoload (autoload 'magit-log-refresh "magit-log" nil t)
(transient-define-prefix magit-log-refresh ()
"Change the arguments used for the log(s) in the current buffer."
:man-page "git-log"
:class 'magit-log-refresh-prefix
[:if-mode magit-log-mode
magit-log-infix-arguments]
magit-log-infix-arguments
[:if-not-mode magit-log-mode
:description "Arguments"
(magit-log:-n)
@@ -652,14 +656,13 @@ commits before and half after."
"Read a string from the user to pass as parameter to OPTION."
(magit-read-string (format "Type a pattern to pass to %s" option)))
;;;###autoload
(defun magit-log-current (revs &optional args files)
"Show log for the current branch.
When `HEAD' is detached or with a prefix argument show log for
one or more revs read from the minibuffer."
(interactive (cons (magit-log-read-revs t)
(magit-log-arguments)))
(magit-log-setup-buffer revs args files))
;;;###autoload (autoload 'magit-log-current "magit-log" nil t)
(transient-define-suffix magit-log-current (&optional args files)
"Show log for the current branch, or `HEAD' if no branch is checked out."
:description (##if (magit-get-current-branch) "current" "HEAD")
(interactive (magit-log-arguments))
(magit-log-setup-buffer (list (or (magit-get-current-branch) "HEAD"))
args files))
;;;###autoload
(defun magit-log-head (&optional args files)
@@ -1147,8 +1150,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
(setq revs (if (< (string-to-number count) limit)
revs
(format "%s~%s..%s" revs limit revs))))
(let ((delay (cl-find-if (lambda (arg)
(member arg '("++header" "--patch" "--stat")))
(let ((delay (cl-find-if (##member % '("++header" "--patch" "--stat"))
args)))
(setq magit-section-inhibit-markers (if delay 'delay t))
(setq magit-section-insert-in-reverse (not delay)))
@@ -1181,10 +1183,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
(defun magit-log-header-line-arguments (revs args files)
"Return string describing some of the used arguments."
(mapconcat (lambda (arg)
(if (string-search " " arg)
(prin1 arg)
arg))
(mapconcat (##if (string-search " " %) (prin1 %) %)
`("git" "log" ,@args ,@revs "--" ,@files)
" "))
@@ -1454,15 +1453,11 @@ Do not add this to a hook variable."
(setq date (+ (string-to-number (match-string 1 date))
(* (string-to-number (match-string 2 date)) 60 60)
(* (string-to-number (match-string 3 date)) 60))))
(save-excursion
(backward-char)
(magit-log-format-margin hash author date)))
(magit-log-format-margin hash author date))
(when (and (eq style 'cherry)
(magit-buffer-margin-p))
(save-excursion
(backward-char)
(apply #'magit-log-format-margin hash
(split-string (magit-rev-format "%aN%x00%ct" hash) "\0"))))
(apply #'magit-log-format-margin hash
(split-string (magit-rev-format "%aN%x00%ct" hash) "\0")))
(when (and graph
(not (eobp))
(not (looking-at non-graph-re)))
@@ -1493,8 +1488,8 @@ Do not add this to a hook variable."
(while (and (not (eobp)) (not (looking-at non-graph-re)))
(when align
(save-excursion (insert align)))
(magit-make-margin-overlay)
(forward-line))
(forward-line)
(magit-make-margin-overlay))
;; When `--format' is used and its value isn't one of the
;; predefined formats, then `git-log' does not insert a
;; separator line.
@@ -1535,7 +1530,8 @@ exists mostly for backward compatibility reasons."
(defun magit-log-maybe-update-revision-buffer (&optional _)
"When moving in a log or cherry buffer, update the revision buffer.
If there is no revision buffer in the same frame, then do nothing."
If there is no revision buffer in the same frame, then do nothing.
See also info node `(magit)Section Movement'."
(when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode)
(magit--maybe-update-revision-buffer)))
@@ -1563,7 +1559,8 @@ If there is no revision buffer in the same frame, then do nothing."
(defun magit-log-maybe-update-blob-buffer (&optional _)
"When moving in a log or cherry buffer, update the blob buffer.
If there is no blob buffer in the same frame, then do nothing."
If there is no blob buffer in the same frame, then do nothing.
See also info node `(magit)Section Movement'."
(when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode)
(magit--maybe-update-blob-buffer)))
@@ -1622,7 +1619,7 @@ The shortstat style is experimental and rather slow."
(magit-log-format-shortstat-margin rev)
(magit-log-format-author-margin author date))))
(defun magit-log-format-author-margin (author date &optional previous-line)
(defun magit-log-format-author-margin (author date)
(pcase-let ((`(,_ ,style ,width ,details ,details-width)
(or magit-buffer-margin
(symbol-value (magit-margin-option))
@@ -1647,8 +1644,7 @@ The shortstat style is experimental and rather slow."
(format (format (if abbr "%%2d%%-%dc" "%%2d %%-%ds")
(- width (if details (1+ details-width) 0)))
cnt unit)))
'magit-log-date))
previous-line)))
'magit-log-date)))))
(defun magit-log-format-shortstat-margin (rev)
(magit-make-margin-overlay

View File

@@ -159,15 +159,16 @@ does not carry to other options."
(and (magit-buffer-margin-p)
(nth 2 magit-buffer-margin))))))
(defun magit-make-margin-overlay (&optional string previous-line)
(if previous-line
(save-excursion
(forward-line -1)
(magit-make-margin-overlay string))
(cl-defun magit-make-margin-overlay (&optional string (previous-line nil sline))
"Display STRING in the margin of the previous (or current) line.
If point is at the beginning of a line, set the margin string for
the previous line, otherwise for the current line. Semi-obsolete
optional PREVIOUS-LINE can be used to explicitly specify which
line is affected."
(save-excursion
(forward-line (if (if sline previous-line (bolp)) -1 0))
;; Don't put the overlay on the complete line to work around #1880.
(let ((o (make-overlay (1+ (line-beginning-position))
(line-end-position)
nil t)))
(let ((o (make-overlay (1+ (point)) (line-end-position) nil t)))
(overlay-put o 'evaporate t)
(overlay-put o 'before-string
(propertize "o" 'display
@@ -177,13 +178,14 @@ does not carry to other options."
(defvar magit-margin-overlay-conditions
'( unpulled unpushed recent stashes local cherries
[remote branchbuf]
[shelved branchbuf]
[tags branchbuf]
topics issues pullreqs))
(defun magit-maybe-make-margin-overlay ()
(when (magit-section-match magit-margin-overlay-conditions
magit-insert-section--current)
(magit-make-margin-overlay nil t)))
(magit-make-margin-overlay)))
;;; Custom Support

View File

@@ -58,7 +58,7 @@
[("p" "Preview merge" magit-merge-preview)
""
("s" "Squash merge" magit-merge-squash)
("i" "Dissolve" magit-merge-into)]]
("d" "Dissolve" magit-merge-dissolve)]]
["Actions"
:if magit-merge-in-progress-p
("m" "Commit merge" magit-commit-create)
@@ -129,7 +129,7 @@ inspect the merge and change the commit message.
(magit-run-git-async "merge" "--no-commit" args rev))
;;;###autoload
(defun magit-merge-into (branch &optional args)
(defun magit-merge-dissolve (branch &optional args)
"Merge the current branch into BRANCH and remove the former.
Before merging, force push the source branch to its push-remote,
@@ -139,14 +139,11 @@ obsolete version of the commits that are being merged. Finally
if `forge-branch-pullreq' was used to create the merged branch,
then also remove the respective remote branch."
(interactive
(list (magit-read-other-local-branch
(format "Merge `%s' into"
(or (magit-get-current-branch)
(magit-rev-parse "HEAD")))
nil
(and-let* ((upstream (magit-get-upstream-branch))
(upstream (cdr (magit-split-branch-name upstream))))
(and (magit-branch-p upstream) upstream)))
(list (let ((branch (magit-get-current-branch)))
(magit-read-other-local-branch
(format "Merge `%s' into" (or branch (magit-rev-parse "HEAD")))
nil
(and branch (magit-get-local-upstream-branch branch))))
(magit-merge-arguments)))
(let ((current (magit-get-current-branch))
(head (magit-rev-parse "HEAD")))
@@ -169,7 +166,7 @@ then also remove the respective remote branch."
(magit-merge-arguments)))
(magit--merge-absorb branch args))
(defun magit--merge-absorb (branch args)
(defun magit--merge-absorb (branch args &optional message)
(when (equal branch (magit-main-branch))
(unless (yes-or-no-p
(format "Do you really want to merge `%s' into another branch? "
@@ -186,7 +183,9 @@ then also remove the respective remote branch."
(magit-process-sentinel process event)
(process-put process 'inhibit-refresh t)
(magit-process-sentinel process event)
(magit--merge-absorb-1 branch args))))))
(magit--merge-absorb-1 branch args))
(when message
(message message))))))
(magit--merge-absorb-1 branch args)))
(defun magit--merge-absorb-1 (branch args)

View File

@@ -398,11 +398,11 @@ recommended value."
":" 'magit-git-command
"r" 'magit-rebase
"R" 'magit-file-rename
"s" 'magit-stage-file
"s" 'magit-stage-files
"S" 'magit-stage-modified
"t" 'magit-tag
"T" 'magit-notes
"u" 'magit-unstage-file
"u" 'magit-unstage-files
"U" 'magit-unstage-all
"v" 'magit-revert-no-commit
"V" 'magit-revert
@@ -570,7 +570,7 @@ Magit is documented in info node `(magit)'."
(magit-hack-dir-local-variables)
(face-remap-add-relative 'header-line 'magit-header-line)
(setq mode-line-process (magit-repository-local-get 'mode-line-process))
(setq-local revert-buffer-function #'magit-refresh-buffer)
(setq-local revert-buffer-function #'magit-revert-buffer)
(setq-local bookmark-make-record-function #'magit--make-bookmark)
(setq-local imenu-create-index-function #'magit--imenu-create-index)
(setq-local imenu-default-goto-function #'magit--imenu-goto-function)
@@ -662,7 +662,7 @@ The buffer's major-mode should derive from `magit-section-mode'."
(magit-display-buffer buffer)
(with-current-buffer buffer
(run-hooks 'magit-setup-buffer-hook)
(magit-refresh-buffer)
(magit-refresh-buffer created)
(when created
(run-hooks 'magit-post-create-buffer-hook)))
buffer))
@@ -889,17 +889,7 @@ If a frame, then only consider buffers on that frame."
(setq magit--default-directory default-directory)
(setq magit-buffer-locked-p (and value t))
(magit-restore-section-visibility-cache mode))
(when magit-uniquify-buffer-names
(cl-pushnew mode uniquify-list-buffers-directory-modes)
(with-current-buffer buffer
(setq list-buffers-directory (abbreviate-file-name default-directory)))
(let ((uniquify-buffer-name-style
(if (memq uniquify-buffer-name-style '(nil forward))
'post-forward-angle-brackets
uniquify-buffer-name-style)))
(uniquify-rationalize-file-buffer-names
name (file-name-directory (directory-file-name default-directory))
buffer)))
(magit--maybe-uniquify-buffer-names buffer name mode)
buffer))
(defun magit-generate-buffer-name-default-function (mode &optional value)
@@ -922,6 +912,19 @@ account."
(?t . ,n)
(?x . ,(if magit-uniquify-buffer-names "" "*"))))))
(defun magit--maybe-uniquify-buffer-names (buffer name mode)
(when magit-uniquify-buffer-names
(cl-pushnew mode uniquify-list-buffers-directory-modes)
(with-current-buffer buffer
(setq list-buffers-directory (abbreviate-file-name default-directory)))
(let ((uniquify-buffer-name-style
(if (memq uniquify-buffer-name-style '(nil forward))
'post-forward-angle-brackets
uniquify-buffer-name-style)))
(uniquify-rationalize-file-buffer-names
name (file-name-directory (directory-file-name default-directory))
buffer))))
;;; Buffer Lock
(defun magit-toggle-buffer-lock ()
@@ -947,16 +950,25 @@ latter is displayed in its place."
(switch-to-buffer unlocked nil t)
(kill-buffer locked))
(setq magit-buffer-locked-p nil)
(rename-buffer (funcall magit-generate-buffer-name-function
major-mode)))
(let ((name (funcall magit-generate-buffer-name-function major-mode))
(buffer (current-buffer))
(mode major-mode))
(rename-buffer (generate-new-buffer-name name))
(with-temp-buffer
(magit--maybe-uniquify-buffer-names buffer name mode))))
(if-let ((value (magit-buffer-value)))
(if-let ((locked (magit-get-mode-buffer major-mode value)))
(let ((unlocked (current-buffer)))
(switch-to-buffer locked nil t)
(kill-buffer unlocked))
(setq magit-buffer-locked-p t)
(rename-buffer (funcall magit-generate-buffer-name-function
major-mode value)))
(let ((name (funcall magit-generate-buffer-name-function
major-mode value))
(buffer (current-buffer))
(mode major-mode))
(rename-buffer (generate-new-buffer-name name))
(with-temp-buffer
(magit--maybe-uniquify-buffer-names buffer name mode))))
(user-error "Buffer has no value it could be locked to"))))
;;; Bury Buffer
@@ -1008,7 +1020,8 @@ window."
Refresh the current buffer if its major mode derives from
`magit-mode', and refresh the corresponding status buffer.
Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
Run hooks `magit-pre-refresh-hook', `magit-post-refresh-hook'
and `magit-unwind-refresh-hook'."
(interactive)
(unless magit-inhibit-refresh
(unwind-protect
@@ -1050,15 +1063,18 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
(with-current-buffer buffer (magit-refresh-buffer)))
(magit-run-hook-with-benchmark 'magit-post-refresh-hook))
(defvar-local magit-refresh-start-time nil)
(defvar-local magit--refresh-start-time nil)
(defun magit-refresh-buffer (&rest _ignore)
(defvar magit--initial-section-hook nil)
(defun magit-refresh-buffer (&optional created)
"Refresh the current Magit buffer."
(interactive)
(setq magit-refresh-start-time (current-time))
(let ((refresh (intern (format "%s-refresh-buffer"
(substring (symbol-name major-mode) 0 -5))))
(magit--refresh-cache (or magit--refresh-cache (list (cons 0 0)))))
(let ((magit--refreshing-buffer-p t)
(magit--refresh-start-time (current-time))
(magit--refresh-cache (or magit--refresh-cache (list (cons 0 0))))
(refresh (intern (format "%s-refresh-buffer"
(substring (symbol-name major-mode) 0 -5)))))
(when (functionp refresh)
(when magit-refresh-verbose
(message "Refreshing buffer `%s'..." (buffer-name)))
@@ -1081,8 +1097,8 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
(deactivate-mark)
(setq magit-section-pre-command-section nil)
(setq magit-section-highlight-overlays nil)
(setq magit-section-selection-overlays nil)
(setq magit-section-highlighted-sections nil)
(setq magit-section-unhighlight-sections nil)
(let ((inhibit-read-only t))
(erase-buffer)
(save-excursion
@@ -1094,12 +1110,22 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
(with-current-buffer buffer
(let ((magit-section-movement-hook nil))
(apply #'magit-section-goto-successor args)))))
(when created
(run-hooks 'magit--initial-section-hook)
(setq-local magit--initial-section-hook nil))
(let ((magit-section-cache-visibility nil))
(magit-section-show magit-root-section))
(run-hooks 'magit-refresh-buffer-hook)
(magit-section-update-highlight)
(set-buffer-modified-p nil))
(set-buffer-modified-p nil)
(push buffer magit-section--refreshed-buffers))
(when magit-refresh-verbose
(message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name)
(float-time (time-since magit-refresh-start-time)))))))
(float-time (time-since magit--refresh-start-time)))))))
(defun magit-revert-buffer (_ignore-auto _noconfirm)
"Wrapper around `magit-refresh-buffer' suitable as `revert-buffer-function'."
(magit-refresh-buffer))
(defun magit-profile-refresh-buffer ()
"Profile refreshing the current Magit buffer."
@@ -1119,9 +1145,8 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
(interactive)
(require (quote elp))
(cond ((catch 'in-progress
(mapatoms (lambda (symbol)
(and (get symbol elp-timer-info-property)
(throw 'in-progress t)))))
(mapatoms (##and (get % elp-timer-info-property)
(throw 'in-progress t))))
(message "Stop profiling and display results...")
(elp-results)
(elp-restore-all))
@@ -1197,14 +1222,12 @@ argument (the prefix) non-nil means save all with no questions."
(when-let ((topdir (magit-rev-parse-safe "--show-toplevel")))
(let ((remote (file-remote-p default-directory))
(save-some-buffers-action-alist
`((?Y (lambda (buffer)
(with-current-buffer buffer
(setq buffer-save-without-query t)
(save-buffer)))
`((?Y ,(##with-current-buffer %
(setq buffer-save-without-query t)
(save-buffer))
"to save the current buffer and remember choice")
(?N (lambda (buffer)
(with-current-buffer buffer
(setq magit-inhibit-refresh-save t)))
(?N ,(##with-current-buffer %
(setq magit-inhibit-refresh-save t))
"to skip the current buffer and remember choice")
,@save-some-buffers-action-alist))
(topdirs nil)

View File

@@ -1,22 +1,18 @@
(define-package "magit" "20250305.2342" "A Git porcelain inside Emacs"
'((emacs "27.1")
(compat "30.0.2.0")
(llama "0.6.1")
(magit-section "4.3.1")
(seq "2.24")
(transient "0.8.5")
(with-editor "3.4.3"))
:commit "225ea6fd009300ba80e55a0162f3e46eb6e4f2d3" :authors
'(("Marius Vollmer" . "marius.vollmer@gmail.com")
("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev"))
:maintainers
'(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")
("Kyle Meyer" . "kyle@kyleam.com"))
:maintainer
'("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")
:keywords
'("git" "tools" "vc")
:url "https://github.com/magit/magit")
;; Local Variables:
;; no-byte-compile: t
;; End:
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "magit" "20250621.2237"
"A Git porcelain inside Emacs."
'((emacs "27.1")
(compat "30.1")
(llama "0.6.3")
(magit-section "4.3.6")
(seq "2.24")
(transient "0.9.0")
(with-editor "3.4.4"))
:url "https://github.com/magit/magit"
:commit "a4f73fb2fb55f7644a80b4442379ef43840ec5e9"
:revdesc "a4f73fb2fb55"
:keywords '("git" "tools" "vc")
:authors '(("Marius Vollmer" . "marius.vollmer@gmail.com")
("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev"))
:maintainers '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")
("Kyle Meyer" . "kyle@kyleam.com")))

View File

@@ -41,6 +41,12 @@
(defvar messages-buffer-name)
(defvar y-or-n-p-map)
(define-obsolete-variable-alias 'magit-process-finish-apply-ansi-colors
'magit-process-apply-ansi-colors "Magit-Section 4.3.2")
(defclass magit-process-section (magit-section)
((process :initform nil)))
;;; Options
(defcustom magit-process-connection-type (not (eq system-type 'cygwin))
@@ -111,9 +117,7 @@ displays the text of `magit-process-error-summary' instead."
(and prog
(string-match-p
"\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog)
(or (cl-loop for (opt val) on args
if (string= opt "--socket")
return val)
(or (cadr (member "--socket" args))
(expand-file-name "~/.git-credential-cache/socket")))))
;; Note: `magit-process-file' is not yet defined when
;; evaluating this form, so we use `process-lines'.
@@ -245,11 +249,54 @@ implement such functions."
:type 'boolean)
(defcustom magit-process-display-mode-line-error t
"Whether Magit should retain and highlight process errors in the mode line."
"Whether Magit should retain and highlight process errors in the mode line.
See `magit-show-process-buffer-hint' for another way to display the
complete output on demand."
:package-version '(magit . "2.12.0")
:group 'magit-process
:type 'boolean)
(defcustom magit-show-process-buffer-hint t
"Whether to append hint about process buffer to Git error messages.
When Magit runs Git for side-effects, the output is always logged to
a per-repository process buffer. If Git exits with a non-zero status,
then a single line of its error output is shown in the repositories
status buffer and in the echo area.
When a user want to learn more about the error, they can switch to that
process buffer, to see the complete output, but initially users are not
aware of this, so Magit appends a usage hint to the error message in
both of these places.
Once you are aware of this, you probably won't need the reminder and can
set this option to nil.
See `magit-process-display-mode-line-error' for another way to display
the complete output on demand."
:package-version '(magit . "4.3.7")
:group 'magit-process
:type 'boolean)
(defcustom magit-process-apply-ansi-colors nil
"Whether and when to apply color escapes in the process buffer.
Magit instructs Git to not colorize its output, but third-party Git
hooks may do so anyway. We recommend you figure out how to prevent
such hooks from colorizing their output instead of customizing this
option.
If `nil' (the default), do not apply color escape sequences. If `t',
apply them once the subprocess has finished. If `filter', apply them
as input arrives (which is more expensive and potentially fragile).
This is a footgun; starter-kits should leave this option untouched."
:package-version '(magit . "4.3.2")
:group 'magit-process
:type '(choice (const :tag "Do not apply" nil)
(const :tag "Apply when subprocess has finished" t)
(const :tag "Apply using process filter" filter)))
(defcustom magit-process-timestamp-format nil
"Format of timestamp for each process in the process buffer.
If non-nil, pass this to `format-time-string' when creating a
@@ -705,9 +752,6 @@ Magit status buffer."
;;; Process Internals
(defclass magit-process-section (magit-section)
((process :initform nil)))
(setf (alist-get 'process magit--section-type-alist) 'magit-process-section)
(defun magit-process-setup (program args)
@@ -843,6 +887,8 @@ Magit status buffer."
(setq string (substring string (1+ ret-pos)))
(delete-region (line-beginning-position) (point)))
(setq string (magit-process-remove-bogus-errors string))
(when (eq magit-process-apply-ansi-colors 'filter)
(setq string (ansi-color-apply string)))
(insert (propertize string 'magit-section
(process-get proc 'section)))
(set-marker (process-mark proc) (point))
@@ -1152,21 +1198,17 @@ If STR is supplied, it replaces the `mode-line-process' text."
(defun magit-process-error-summary (process-buf section)
"A one-line error summary from the given SECTION."
(or (and (buffer-live-p process-buf)
(with-current-buffer process-buf
(and (oref section content)
(save-excursion
(goto-char (oref section end))
(run-hook-wrapped
'magit-process-error-message-regexps
(lambda (re)
(save-excursion
(and (re-search-backward
re (oref section start) t)
(or (match-string-no-properties 1)
(and (not magit-process-raise-error)
'suppressed))))))))))
"Git failed"))
(and (buffer-live-p process-buf)
(with-current-buffer process-buf
(and (oref section content)
(save-excursion
(goto-char (oref section end))
(run-hook-wrapped
'magit-process-error-message-regexps
(lambda (re)
(save-excursion
(and (re-search-backward re (oref section start) t)
(match-string-no-properties 1))))))))))
(defun magit-process-error-tooltip (process-buf section)
"Returns the text from SECTION of the PROCESS-BUF buffer.
@@ -1195,13 +1237,10 @@ Limited by `magit-process-error-tooltip-max-lines'."
(defvar-local magit-this-error nil)
(defvar magit-process-finish-apply-ansi-colors nil)
(defun magit-process-finish (arg &optional process-buf command-buf
(defun magit-process-finish (arg &optional process-buf _command-buf
default-dir section)
(unless (integerp arg)
(setq process-buf (process-buffer arg))
(setq command-buf (process-get arg 'command-buf))
(setq default-dir (process-get arg 'default-dir))
(setq section (process-get arg 'section))
(setq arg (process-exit-status arg)))
@@ -1211,35 +1250,28 @@ Limited by `magit-process-error-tooltip-max-lines'."
(with-current-buffer process-buf
(magit-process-finish-section section arg)))
(if (= arg 0)
;; Unset the `mode-line-process' value upon success.
(magit-process-unset-mode-line default-dir)
;; Otherwise process the error.
(let ((msg (magit-process-error-summary process-buf section)))
;; Change `mode-line-process' to an error face upon failure.
(if magit-process-display-mode-line-error
(magit-process-set-mode-line-error-status
(or (magit-process-error-tooltip process-buf section)
msg))
(or (magit-process-error-tooltip process-buf section) msg))
(magit-process-unset-mode-line default-dir))
;; Either signal the error, or else display the error summary in
;; the status buffer and with a message in the echo area.
(cond
(magit-process-raise-error
(signal 'magit-git-error (list (format "%s (in %s)" msg default-dir))))
((not (eq msg 'suppressed))
(when (buffer-live-p process-buf)
(with-current-buffer process-buf
(when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode)))
(with-current-buffer status-buf
(setq magit-this-error msg)))))
(message "%s ... [%s buffer %s for details]" msg
(if-let ((key (and (buffer-live-p command-buf)
(with-current-buffer command-buf
(car (where-is-internal
'magit-process-buffer))))))
(format "Hit %s to see" (key-description key))
"See")
(buffer-name process-buf))))))
(when (buffer-live-p process-buf)
(with-current-buffer process-buf
(when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode)))
(with-current-buffer status-buf
(setq magit-this-error msg)))))
(let ((usage
(and magit-show-process-buffer-hint
(if-let ((keys (where-is-internal 'magit-process-buffer)))
(format "Type %s to see %S for details"
(key-description (car keys)) process-buf)
(format "See %S for details" process-buf)))))
(if magit-process-raise-error
(signal 'magit-git-error
(list msg (or usage (list 'in default-dir))))
(message "Git error: %s"
(concat msg (and usage (format " [%s]" usage))))))))
arg)
(defun magit-process-finish-section (section exit-code)
@@ -1256,7 +1288,7 @@ Limited by `magit-process-error-tooltip-max-lines'."
'magit-process-ok
'magit-process-ng)))
(set-marker-insertion-type marker t))
(when magit-process-finish-apply-ansi-colors
(when (eq magit-process-apply-ansi-colors t)
(ansi-color-apply-on-region (oref section content)
(oref section end)))
(if (= (oref section end)

View File

@@ -39,13 +39,13 @@
("-F" "Force" ("-f" "--force"))
("-h" "Disable hooks" "--no-verify")
("-n" "Dry run" ("-n" "--dry-run"))
(5 "-u" "Set upstream" "--set-upstream")
(7 "-t" "Follow tags" "--follow-tags")]
("-u" "Set upstream" "--set-upstream" :level 5)
("-T" "Include all tags" "--tags")
("-t" "Include related annotated tags" "--follow-tags")]
[:if magit-get-current-branch
:description (lambda ()
(format (propertize "Push %s to" 'face 'transient-heading)
:description (##format (propertize "Push %s to" 'face 'transient-heading)
(propertize (magit-get-current-branch)
'face 'magit-branch-local)))
'face 'magit-branch-local))
("p" magit-push-current-to-pushremote)
("u" magit-push-current-to-upstream)
("e" "elsewhere" magit-push-current)]

View File

@@ -63,7 +63,7 @@ To change the value in an existing buffer use the command
`magit-refs-set-show-commit-count'."
:package-version '(magit . "2.1.0")
:group 'magit-refs
:safe (lambda (val) (memq val '(all branch nil)))
:safe (##memq % '(all branch nil))
:type '(choice (const :tag "For branches and tags" all)
(const :tag "For branches only" branch)
(const :tag "Never" nil)))
@@ -134,7 +134,7 @@ AUTHOR-WIDTH has to be an integer. When the name of the author
:package-version '(magit . "2.9.0")
:group 'magit-refs
:group 'magit-margin
:safe (lambda (val) (memq val '(all branch nil)))
:safe (##memq % '(all branch nil))
:type magit-log-margin--custom-type
:initialize #'magit-custom-initialize-reset
:set-after '(magit-log-margin)
@@ -333,8 +333,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
(transient-define-prefix magit-show-refs (&optional transient)
"List and compare references in a dedicated buffer."
:man-page "git-branch"
:value (lambda ()
(magit-show-refs-arguments magit-prefix-use-buffer-arguments))
:value (##magit-show-refs-arguments magit-prefix-use-buffer-arguments)
["Arguments"
(magit-for-each-ref:--contains)
("-M" "Merged" "--merged=" magit-transient-read-revision)
@@ -566,7 +565,7 @@ line is inserted at all."
(magit-refs--format-margin tag))
(magit-refs--insert-cherry-commits tag)))))
(insert ?\n)
(magit-make-margin-overlay nil t)))))
(magit-make-margin-overlay)))))
(defun magit-insert-remote-branches ()
"Insert sections showing all remote-tracking branches."
@@ -621,7 +620,7 @@ line is inserted at all."
(magit-refs--format-margin branch))
(magit-refs--insert-cherry-commits branch))))))))
(insert ?\n)
(magit-make-margin-overlay nil t))))
(magit-make-margin-overlay))))
(defun magit-insert-local-branches ()
"Insert sections showing all local branches."
@@ -638,7 +637,22 @@ line is inserted at all."
(magit-refs--format-margin branch))
(magit-refs--insert-cherry-commits branch))))
(insert ?\n)
(magit-make-margin-overlay nil t)))
(magit-make-margin-overlay)))
(defun magit-insert-shelved-branches ()
"Insert sections showing all shelved branches."
(when-let ((refs (magit-list-refs "refs/shelved/")))
(magit-insert-section (shelved nil)
(magit-insert-heading t "Shelved branches")
(dolist (ref (nreverse refs))
(magit-insert-section (shelved-branch ref t)
(magit-insert-heading
" " (magit--propertize-face (substring ref 13) 'magit-refname))
(when (magit-buffer-margin-p)
(magit-refs--format-margin ref))
(magit-refs--insert-cherry-commits ref)))
(insert ?\n)
(magit-make-margin-overlay))))
(defun magit-refs--format-local-branches ()
(let ((lines (seq-keep #'magit-refs--format-local-branch
@@ -788,15 +802,12 @@ line is inserted at all."
"cherry" "-v" (magit-abbrev-arg) magit-buffer-upstream ref)
(if (= (point) start)
(message "No cherries for %s" ref)
(magit-make-margin-overlay nil t)))))
(magit-make-margin-overlay)))))
(defun magit-refs--format-margin (commit)
(save-excursion
(goto-char (line-beginning-position 0))
(let ((line (magit-rev-format "%ct%cN" commit)))
(magit-log-format-margin commit
(substring line 10)
(substring line 0 10)))))
(if-let ((line (magit-rev-format "%cN%x00%ct" commit)))
(apply #'magit-log-format-margin commit (split-string line "\0"))
(magit-make-margin-overlay)))
;;; _
(provide 'magit-refs)

View File

@@ -68,7 +68,7 @@ has to be used to view and change remote related variables."
:man-page "git-remote"
:value '("-f")
["Variables"
:if (lambda () (and magit-remote-direct-configure (transient-scope)))
:if (##and magit-remote-direct-configure (transient-scope))
("u" magit-remote.<remote>.url)
("U" magit-remote.<remote>.fetch)
("s" magit-remote.<remote>.pushurl)
@@ -210,13 +210,11 @@ the now stale refspecs. Other stale branches are not removed."
nil refs))
(magit-confirm 'prune-stale-refspecs nil
(format "Prune %%d stale refspecs and %d branches"
(length (mapcan (lambda (s) (copy-sequence (cdr s)))
stale)))
(length (mapcan (##copy-sequence (cdr %)) stale)))
nil
(mapcar (pcase-lambda (`(,refspec . ,refs))
(concat refspec "\n"
(mapconcat (lambda (b) (concat " " b))
refs "\n")))
(mapconcat (##concat " " %) refs "\n")))
stale)))
(pcase-dolist (`(,refspec . ,refs) stale)
(magit-call-git "config" "--unset" variable
@@ -311,10 +309,9 @@ refspec."
(transient-define-prefix magit-remote-configure (remote)
"Configure a remote."
:man-page "git-remote"
[:description
(lambda ()
(concat (propertize "Configure " 'face 'transient-heading)
(propertize (transient-scope) 'face 'magit-branch-remote)))
[:description (##concat
(propertize "Configure " 'face 'transient-heading)
(propertize (transient-scope) 'face 'magit-branch-remote))
("u" magit-remote.<remote>.url)
("U" magit-remote.<remote>.fetch)
("s" magit-remote.<remote>.pushurl)

View File

@@ -31,7 +31,7 @@
(require 'magit)
;; For `magit-rebase--todo'.
(declare-function git-rebase-current-line "git-rebase" ())
(declare-function git-rebase-current-line "git-rebase" (&optional batch))
(eval-when-compile
(cl-pushnew 'action-type eieio--known-slot-names)
(cl-pushnew 'action eieio--known-slot-names)
@@ -528,11 +528,11 @@ This discards all changes made since the sequence started."
:if-not magit-rebase-in-progress-p
("-k" "Keep empty commits" "--keep-empty")
("-p" "Preserve merges" ("-p" "--preserve-merges")
:if (lambda () (magit-git-version< "2.33.0")))
:if (##magit-git-version< "2.33.0"))
("-r" "Rebase merges" ("-r" "--rebase-merges=")
magit-rebase-merges-select-mode)
("-u" "Update branches" "--update-refs"
:if (lambda () (magit-git-version>= "2.38.0")))
:if (##magit-git-version>= "2.38.0"))
(7 magit-merge:--strategy)
(7 magit-merge:--strategy-option)
(7 "=X" magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=")
@@ -547,10 +547,9 @@ This discards all changes made since the sequence started."
(magit:--gpg-sign)
(magit:--signoff)]
[:if-not magit-rebase-in-progress-p
:description (lambda ()
(format (propertize "Rebase %s onto" 'face 'transient-heading)
:description (##format (propertize "Rebase %s onto" 'face 'transient-heading)
(propertize (or (magit-get-current-branch) "HEAD")
'face 'magit-branch-local)))
'face 'magit-branch-local))
("p" magit-rebase-onto-pushremote)
("u" magit-rebase-onto-upstream)
("e" "elsewhere" magit-rebase-branch)]
@@ -675,17 +674,13 @@ START has to be selected from a list of recent commits."
(commit args message &optional editor delay-edit-confirm noassert confirm)
(declare (indent 2))
(when commit
(if (eq commit :merge-base)
(setq commit
(and-let* ((upstream (magit-get-upstream-branch)))
(magit-git-string "merge-base" upstream "HEAD")))
(unless (magit-rev-ancestor-p commit "HEAD")
(user-error "%s isn't an ancestor of HEAD" commit))
(if (magit-commit-parents commit)
(when (or (not (eq this-command 'magit-rebase-interactive))
magit-rebase-interactive-include-selected)
(setq commit (concat commit "^")))
(setq args (cons "--root" args)))))
(unless (magit-rev-ancestor-p commit "HEAD")
(user-error "%s isn't an ancestor of HEAD" commit))
(if (magit-commit-parents commit)
(when (or (not (eq this-command 'magit-rebase-interactive))
magit-rebase-interactive-include-selected)
(setq commit (concat commit "^")))
(setq args (cons "--root" args))))
(when (and commit (not noassert))
(setq commit (magit-rebase-interactive-assert
commit delay-edit-confirm
@@ -761,10 +756,17 @@ START has to be selected from a list of recent commits."
nil t))
;;;###autoload
(defun magit-rebase-autosquash (args)
"Combine squash and fixup commits with their intended targets."
(interactive (list (magit-rebase-arguments)))
(magit-rebase-interactive-1 :merge-base
(defun magit-rebase-autosquash (select args)
"Combine squash and fixup commits with their intended targets.
By default only squash into commits that are not reachable from
the upstream branch. If no upstream is configured or with a prefix
argument, prompt for the first commit to potentially squash into."
(interactive (list current-prefix-arg
(magit-rebase-arguments)))
(magit-rebase-interactive-1
(and-let* (((not select))
(upstream (magit-get-upstream-branch)))
(magit-git-string "merge-base" upstream "HEAD"))
(nconc (list "--autosquash" "--keep-empty") args)
"Type %p on a commit to squash into it and then rebase as necessary,"
"true" nil t))
@@ -966,9 +968,8 @@ If no such sequence is in progress, do nothing."
If no such sequence is in progress, do nothing."
(when (magit-rebase-in-progress-p)
(let* ((gitdir (magit-gitdir))
(interactive
(file-directory-p (expand-file-name "rebase-merge" gitdir)))
(dir (if interactive "rebase-merge/" "rebase-apply/"))
(mergep (file-directory-p (expand-file-name "rebase-merge" gitdir)))
(dir (if mergep "rebase-merge/" "rebase-apply/"))
(name (thread-first (concat dir "head-name")
(expand-file-name gitdir)
magit-file-line))
@@ -980,7 +981,7 @@ If no such sequence is in progress, do nothing."
(name (or (magit-rev-name name "refs/heads/*") name)))
(magit-insert-section (rebase-sequence)
(magit-insert-heading (format "Rebasing %s onto %s" name onto))
(if interactive
(if mergep
(magit-rebase-insert-merge-sequence onto)
(magit-rebase-insert-apply-sequence onto))
(insert ?\n)))))
@@ -990,36 +991,42 @@ If no such sequence is in progress, do nothing."
These are ordered in that the same way they'll be sorted in the
status buffer (i.e., the reverse of how they will be applied)."
(let ((comment-start (or (magit-get "core.commentChar") "#"))
lines)
(commits ())
(actions ()))
(with-temp-buffer
(insert-file-contents
(expand-file-name "rebase-merge/git-rebase-todo" (magit-gitdir)))
(while (not (eobp))
(let ((ln (git-rebase-current-line)))
(when (oref ln action-type)
(push ln lines)))
(when-let ((obj (git-rebase-current-line t)))
(push obj actions)
(when (memq (oref obj action-type) '(commit merge))
(push obj commits)))
(forward-line)))
lines))
(let ((abbrevs
(and commits
(magit-git-lines
"log" "--no-walk=unsorted" "--format=%h"
(mapcar (lambda (obj)
(if (eq (oref obj action-type) 'merge)
(let ((options (oref obj action-options)))
(and (string-match "-[cC] \\([^ ]+\\)" options)
(match-string 1 options)))
(oref obj target)))
commits)))))
(cl-assert (equal (length commits) (length abbrevs)))
(while-let ((obj (pop commits))
(val (pop abbrevs)))
(oset obj abbrev val)))
actions))
(defun magit-rebase-insert-merge-sequence (onto)
(dolist (line (magit-rebase--todo))
(with-slots (action-type action action-options target) line
(dolist (obj (magit-rebase--todo))
(with-slots (action-type action action-options target abbrev trailer) obj
(pcase action-type
('commit
(magit-sequence-insert-commit action target 'magit-sequence-pick))
((or (or `exec `label)
(and `merge (guard (not action-options))))
(insert (propertize action 'font-lock-face 'magit-sequence-onto) "\s"
(propertize target 'font-lock-face 'git-rebase-label) "\n"))
('merge
(if-let ((hash (and (string-match "-[cC] \\([^ ]+\\)" action-options)
(match-string 1 action-options))))
(magit-insert-section (commit hash)
(magit-insert-heading
(propertize "merge" 'font-lock-face 'magit-sequence-pick)
"\s"
(magit-format-rev-summary hash) "\n"))
(error "Failed to parse merge message hash"))))))
((or 'commit (and 'merge (guard abbrev)))
(magit-sequence-insert-commit action target 'magit-sequence-pick
abbrev trailer))
((guard action) (magit-sequence-insert-step action target)))))
(let ((dir (magit-gitdir)))
(magit-sequence-insert-sequence
(magit-file-line (expand-file-name "rebase-merge/stopped-sha" dir))
@@ -1052,13 +1059,15 @@ status buffer (i.e., the reverse of how they will be applied)."
(defun magit-sequence-insert-sequence (stop onto &optional orig)
(let ((head (magit-rev-parse "HEAD")) done)
(setq onto (if onto (magit-rev-parse onto) head))
(setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD")))
(when (and stop (not (member (magit-rev-parse stop) done)))
(setq done (mapcar (##split-string % "\0")
(magit-git-lines "log" "--format=%H%x00%h%x00%s"
(concat onto "..HEAD"))))
(when (and stop (not (assoc (magit-rev-parse stop) done)))
(let ((id (magit-patch-id stop)))
(if-let ((matched (seq-find (##equal (magit-patch-id %) id) done)))
(if-let ((matched (car (assoc (##equal (magit-patch-id %) id) done))))
(setq stop matched)
(cond
((seq-find (##magit-rev-equal % stop) done)
((assoc (##magit-rev-equal % stop) done)
;; The commit's testament has been executed.
(magit-sequence-insert-commit "void" stop 'magit-sequence-drop))
;; The faith of the commit is still undecided...
@@ -1084,14 +1093,14 @@ status buffer (i.e., the reverse of how they will be applied)."
(t "work")))
stop 'magit-sequence-part))
;; The commit is definitely gone...
((seq-find (##magit-rev-equal % stop) done)
((assoc (##magit-rev-equal % stop) done)
;; ...but all of its changes are still in effect.
(magit-sequence-insert-commit "poof" stop 'magit-sequence-drop))
(t
;; ...and some changes are gone and/or other changes were added.
(magit-sequence-insert-commit "gone" stop 'magit-sequence-drop)))
(setq stop nil))))
(dolist (rev done)
(pcase-dolist (`(,rev ,abbrev ,msg) done)
(apply #'magit-sequence-insert-commit
(cond ((equal rev stop)
;; ...but its reincarnation lives on.
@@ -1103,21 +1112,32 @@ status buffer (i.e., the reverse of how they will be applied)."
"like") ; There are new commits.
rev (if (equal rev head)
'magit-sequence-head
'magit-sequence-stop)))
'magit-sequence-stop)
abbrev msg))
((equal rev head)
(list "done" rev 'magit-sequence-head))
(list "done" rev 'magit-sequence-head abbrev msg))
(t
(list "done" rev 'magit-sequence-done)))))
(list "done" rev 'magit-sequence-done abbrev msg)))))
(magit-sequence-insert-commit "onto" onto
(if (equal onto head)
'magit-sequence-head
'magit-sequence-onto))))
(defun magit-sequence-insert-commit (type hash face)
(defun magit-sequence-insert-commit (type hash face &optional abbrev msg)
(magit-insert-section (commit hash)
(magit-insert-heading
(propertize type 'font-lock-face face) "\s"
(magit-format-rev-summary hash) "\n")))
(propertize type 'font-lock-face face) " "
(if abbrev
(concat (propertize abbrev 'face 'magit-hash) " " msg "\n")
(concat (magit-format-rev-summary hash) "\n")))))
(defun magit-sequence-insert-step (type target)
(magit-insert-section (rebase-step (cons type target))
(magit-insert-heading
(propertize type 'font-lock-face 'magit-sequence-pick)
(and target
(concat "\s"
(propertize target 'font-lock-face 'git-rebase-label))))))
;;; _
(provide 'magit-sequence)

View File

@@ -113,7 +113,7 @@ directories, call `magit-sparse-checkout-set' instead."
(let ((re (concat
"\\`"
(regexp-opt (magit-sparse-checkout-directories)))))
(lambda (d) (string-match-p re d)))
(##string-match-p re %))
(magit-revision-directories "HEAD")))))
(magit-sparse-checkout--auto-enable)
(magit-run-git-async "sparse-checkout" "add" directories))

View File

@@ -173,14 +173,15 @@ while two prefix arguments are equivalent to `--all'."
The message that Git would have picked, is available as the
default (used when the user enters the empty string) and as
the next history element (which can be accessed with \
\\<minibuffer-local-map>\\[next-history-element])."
(read-string (format "Stash message (default: On%s:%s): "
(magit--ellipsis) (magit--ellipsis))
nil nil
(format "On %s: %s"
(or (magit-get-current-branch) "(no branch)")
(magit-rev-format "%h %s"))))
the first future history element. The second future history
element is just \"On BRANCH: \". Future history elements can
be accessed using \\<minibuffer-local-map>\\[next-history-element])."
(let ((branch (or (magit-get-current-branch) "(no branch)"))
(ellipsis (magit--ellipsis)))
(read-string (format "Stash message (default: On%s:%s): " ellipsis ellipsis)
nil nil
(list (format "On %s: %s" branch (magit-rev-format "%h %s"))
(format "On %s: " branch)))))
(defun magit-stash-read-message-traditional ()
"Read a message from the minibuffer, to be used for a stash.
@@ -330,7 +331,7 @@ want to fall back to using \"--3way\", without being prompted."
(concat
"Could not apply stash because of unstaged changes.\n\n"
"To do a tree-way merge, these files have to be staged\n"
(mapconcat (lambda (f) (format " %s" f)) conflicts "\n")
(mapconcat (##format " %s" %) conflicts "\n")
"\n")
nil
(?s (format
@@ -527,16 +528,12 @@ instead of \"Stashes:\"."
(magit-insert-section (stash autostash)
(insert (propertize "AUTOSTASH" 'font-lock-face 'magit-hash))
(insert " " msg "\n")
(save-excursion
(backward-char)
(magit-log-format-margin autostash author date)))))
(magit-log-format-margin autostash author date))))
(if verified
(magit-git-wash (apply-partially #'magit-log-wash-log 'stash)
"reflog" "--format=%gd%x00%aN%x00%at%x00%gs" ref)
(insert ?\n)
(save-excursion
(backward-char)
(magit-make-margin-overlay)))))))
(magit-make-margin-overlay))))))
;;; List Stashes
@@ -572,7 +569,8 @@ instead of \"Stashes:\"."
(defun magit-stashes-maybe-update-stash-buffer (&optional _)
"When moving in the stashes buffer, update the stash buffer.
If there is no stash buffer in the same frame, then do nothing."
If there is no stash buffer in the same frame, then do nothing.
See also info node `(magit)Section Movement'."
(when (derived-mode-p 'magit-stashes-mode)
(magit--maybe-update-stash-buffer)))

View File

@@ -174,8 +174,10 @@ of the work Git is responsible for. Turning that list into sections is
also not free, so Magit only lists `magit-status-file-list-limit' files."
:package-version '(magit . "4.3.0")
:group 'magit-status
:type 'boolean
:safe 'booleanp)
:type '(choice (const :tag "Do not list untracked files" nil)
(const :tag "List mixture of files and directories" t)
(const :tag "List individual files (slow)" all))
:safe (##memq % '(nil t all)))
(defcustom magit-status-file-list-limit 100
"How many files to list in file list sections in the status buffer.
@@ -432,7 +434,7 @@ Type \\[magit-commit] to create a commit.
:group 'magit-status
(magit-hack-dir-local-variables)
(when magit-status-initial-section
(add-hook 'magit-post-create-buffer-hook
(add-hook 'magit--initial-section-hook
#'magit-status-goto-initial-section nil t))
(setq magit--imenu-group-types '(not branch commit)))
@@ -498,19 +500,22 @@ Type \\[magit-commit] to create a commit.
(defun magit-status-maybe-update-revision-buffer (&optional _)
"When moving in the status buffer, update the revision buffer.
If there is no revision buffer in the same frame, then do nothing."
If there is no revision buffer in the same frame, then do nothing.
See also info node `(magit)Section Movement'."
(when (derived-mode-p 'magit-status-mode)
(magit--maybe-update-revision-buffer)))
(defun magit-status-maybe-update-stash-buffer (&optional _)
"When moving in the status buffer, update the stash buffer.
If there is no stash buffer in the same frame, then do nothing."
If there is no stash buffer in the same frame, then do nothing.
See also info node `(magit)Section Movement'."
(when (derived-mode-p 'magit-status-mode)
(magit--maybe-update-stash-buffer)))
(defun magit-status-maybe-update-blob-buffer (&optional _)
"When moving in the status buffer, update the blob buffer.
If there is no blob buffer in the same frame, then do nothing."
If there is no blob buffer in the same frame, then do nothing.
See also info node `(magit)Section Movement'."
(when (derived-mode-p 'magit-status-mode)
(magit--maybe-update-blob-buffer)))
@@ -542,7 +547,8 @@ the status buffer causes this section to disappear again."
(insert (propertize (format "%-10s" "GitError! ")
'font-lock-face 'magit-section-heading))
(insert (propertize magit-this-error 'font-lock-face 'error))
(when-let ((key (car (where-is-internal 'magit-process-buffer))))
(when-let ((magit-show-process-buffer-hint)
(key (car (where-is-internal 'magit-process-buffer))))
(insert (format " [Type `%s' for details]" (key-description key))))
(insert ?\n))
(setq magit-this-error nil)))
@@ -568,13 +574,12 @@ the status buffer causes this section to disappear again."
"Insert a header line about the current branch.
If `HEAD' is detached, then insert information about that commit
instead. The optional BRANCH argument is for internal use only."
(let ((branch (or branch (magit-get-current-branch)))
(output (magit-rev-format "%h %s" (or branch "HEAD"))))
(let ((output (magit-rev-format "%h %s" (or branch "HEAD"))))
(string-match "^\\([^ ]+\\) \\(.*\\)" output)
(magit-bind-match-strings (commit summary) output
(when (equal summary "")
(setq summary "(no commit message)"))
(if branch
(if-let ((branch (or branch (magit-get-current-branch))))
(magit-insert-section (branch branch)
(insert (format "%-10s" "Head: "))
(when magit-status-show-hashes-in-headers
@@ -726,7 +731,7 @@ remote in alphabetic order."
(defvar-keymap magit-untracked-section-map
:doc "Keymap for the `untracked' section."
"<remap> <magit-delete-thing>" #'magit-discard
"<remap> <magit-stage-file>" #'magit-stage
"<remap> <magit-stage-files>" #'magit-stage
"<2>" (magit-menu-item "Discard files" #'magit-discard)
"<1>" (magit-menu-item "Stage files" #'magit-stage))
@@ -766,9 +771,8 @@ is always ignored."
(magit-insert-files
'untracked
(lambda (files)
(mapcan (lambda (line)
(and (eq (aref line 0) ??)
(list (substring line 3))))
(mapcan (##and (eq (aref % 0) ??)
(list (substring % 3)))
(apply #'magit-git-items "status" "-z" "--porcelain"
(format "--untracked-files=%s"
(if (eq value 'all) "all" "normal"))
@@ -782,8 +786,7 @@ Honor the buffer's file filter, which can be set using \"D - -\"."
(defun magit-insert-ignored-files ()
"Insert a list of ignored files.
Honor the buffer's file filter, which can be set using \"D - -\"."
(magit-insert-files 'ignored
(lambda (args) (magit-ignored-files "--directory" args))))
(magit-insert-files 'ignored (##magit-ignored-files "--directory" %)))
(defun magit-insert-skip-worktree-files ()
"Insert a list of skip-worktree files.

View File

@@ -30,8 +30,6 @@
(require 'magit)
(defvar x-stretch-cursor)
;;; Options
(defcustom magit-module-sections-hook
@@ -220,26 +218,20 @@ it is nil, then PATH also becomes the name."
(interactive
(magit-with-toplevel
(let* ((url (magit-read-string-ns "Add submodule (remote url)"))
(path (let ((read-file-name-function
(if (or (eq read-file-name-function 'ido-read-file-name)
(advice-function-member-p
'ido-read-file-name
read-file-name-function))
;; The Ido variant doesn't work properly here.
#'read-file-name-default
read-file-name-function)))
(directory-file-name
(file-relative-name
(read-directory-name
"Add submodules at path: " nil nil nil
(and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
(match-string 1 url))))))))
(path (magit-submodule-read-path "Add submodules at path: " url)))
(list url
(directory-file-name path)
(magit-submodule-read-name-for-path path)
(magit-submodule-arguments "--force")))))
(magit-submodule-add-1 url path name args))
(defun magit-submodule-read-path (prompt url)
(directory-file-name
(file-relative-name
(read-directory-name prompt nil nil nil
(and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
(match-string 1 url))))))
(defun magit-submodule-add-1 (url &optional path name args)
(magit-with-toplevel
(magit-submodule--maybe-reuse-gitdir name path)
@@ -525,9 +517,9 @@ or, failing that, the abbreviated HEAD commit hash."
:doc "Keymap for `module' sections."
"C-j" #'magit-submodule-visit
"C-<return>" #'magit-submodule-visit
"<remap> <magit-unstage-file>" #'magit-unstage
"<remap> <magit-stage-file>" #'magit-stage
"<remap> <magit-visit-thing>" #'magit-submodule-visit
"<remap> <magit-unstage-files>" #'magit-unstage
"<remap> <magit-stage-files>" #'magit-stage
"<remap> <magit-visit-thing>" #'magit-submodule-visit
"<5>" (magit-menu-item "Module commands..." #'magit-submodule)
"<4>" '(menu-item "--")
"<3>" (magit-menu-item "Unstage %T" #'magit-unstage

View File

@@ -82,7 +82,6 @@
(topdir (magit-toplevel))
(prefix (read-directory-name (concat prompt ": ") topdir default)))
(if (file-name-absolute-p prefix)
;; At least `ido-mode's variant is not compatible.
(if (string-prefix-p topdir prefix)
(file-relative-name prefix topdir)
(user-error "%s isn't inside the repository at %s" prefix topdir))

View File

@@ -93,19 +93,27 @@
(let ((choices (oref obj choices)))
(when (functionp choices)
(setq choices (funcall choices)))
(if-let ((value (oref obj value)))
(cadr (member value choices))
(car choices))))
(if current-prefix-arg
(pcase-let*
((`(,fallback . ,choices)
(magit--git-variable-list-choices obj))
(choice (magit-completing-read
(format "Set `%s' to" (oref obj variable))
(if fallback (nconc choices (list fallback)) choices)
nil t)))
(if (equal choice fallback) nil choice))
(if-let ((value (oref obj value)))
(cadr (member value choices))
(car choices)))))
;;;; Readers
(defun magit-transient-read-person (prompt initial-input history)
(magit-completing-read
prompt
(mapcar (lambda (line)
(save-excursion
(and (string-match "\\`[\s\t]+[0-9]+\t" line)
(list (substring line (match-end 0))))))
(mapcar (##save-excursion
(and (string-match "\\`[\s\t]+[0-9]+\t" %)
(list (substring % (match-end 0)))))
(magit-git-lines "shortlog" "-n" "-s" "-e" "HEAD"))
nil nil initial-input history))
@@ -151,9 +159,8 @@
(if-let ((value (oref obj value)))
(if (oref obj multi-value)
(if (cdr value)
(mapconcat (lambda (v)
(concat "\n "
(propertize v 'face 'transient-value)))
(mapconcat (##concat "\n "
(propertize % 'face 'transient-value))
value "")
(propertize (car value) 'face 'transient-value))
(propertize (car (split-string value "\n"))
@@ -165,6 +172,16 @@
(propertize "unset" 'face 'transient-inactive-value))))
(cl-defmethod transient-format-value ((obj magit--git-variable:choices))
(pcase-let ((`(,fallback . ,choices) (magit--git-variable-list-choices obj)))
(concat
(propertize "[" 'face 'transient-inactive-value)
(mapconcat #'identity choices
(propertize "|" 'face 'transient-inactive-value))
(and fallback (propertize "|" 'face 'transient-inactive-value))
fallback
(propertize "]" 'face 'transient-inactive-value))))
(defun magit--git-variable-list-choices (obj)
(let* ((variable (oref obj variable))
(choices (oref obj choices))
(globalp (oref obj global))
@@ -182,42 +199,35 @@
(setq global nil))
(when (functionp choices)
(setq choices (funcall choices)))
(concat
(propertize "[" 'face 'transient-inactive-value)
(mapconcat (lambda (choice)
(propertize choice 'face (if (equal choice value)
(if (member choice choices)
'transient-value
'font-lock-warning-face)
'transient-inactive-value)))
(if (and value (not (member value choices)))
(cons value choices)
choices)
(propertize "|" 'face 'transient-inactive-value))
(and (or global fallback default)
(concat
(propertize "|" 'face 'transient-inactive-value)
(cond (global
(propertize (concat "global:" global)
'face (cond (value
'transient-inactive-value)
((member global choices)
'transient-value)
(t
'font-lock-warning-face))))
(fallback
(propertize fallback
'face (if value
'transient-inactive-value
'transient-value)))
(default
(propertize (if (functionp defaultp)
(concat "dwim:" default)
(concat "default:" default))
'face (if value
'transient-inactive-value
'transient-value))))))
(propertize "]" 'face 'transient-inactive-value))))
(cons (cond (global
(propertize (concat "global:" global)
'face (cond (value
'transient-inactive-value)
((member global choices)
'transient-value)
(t
'font-lock-warning-face))))
(fallback
(propertize fallback
'face (if value
'transient-inactive-value
'transient-value)))
(default
(propertize (if (functionp defaultp)
(concat "dwim:" default)
(concat "default:" default))
'face (if value
'transient-inactive-value
'transient-value))))
(mapcar (lambda (choice)
(propertize choice 'face (if (equal choice value)
(if (member choice choices)
'transient-value
'font-lock-warning-face)
'transient-inactive-value)))
(if (and value (not (member value choices)))
(cons value choices)
choices)))))
;;; Utilities

View File

@@ -1,8 +1,8 @@
;;; magit-version.el --- the Magit version you are using
;;; magit-version.el --- The Magit version you are using -*- lexical-binding:t -*-
(setq magit-version "4.3.1")
(setq magit-version "4.3.6")
(provide 'migit-version)
(provide 'magit-version)
;; Local Variables:
;; version-control: never

View File

@@ -435,6 +435,27 @@ many \"branches\" of each wip ref are shown."
(cl-decf count))
(cons wipref (nreverse tips)))))
(defun magit-wip-purge ()
"Ask to delete all wip-refs that no longer have a corresponding ref."
(interactive)
(if-let ((wiprefs (thread-last
(cl-set-difference (magit-list-refs "refs/wip/")
(magit-list-refs)
:test (##equal (substring %1 15) %2))
(delete "refs/wip/index/HEAD")
(delete "refs/wip/wtree/HEAD"))))
(progn
(magit-confirm 'purge-dangling-wiprefs
"Delete wip-ref %s without corresponding ref"
"Delete %d wip-refs without corresponding ref"
nil wiprefs)
(message "Deleting wip-refs...")
(dolist (wipref wiprefs)
(magit-call-git "update-ref" "-d" wipref))
(message "Deleting wip-refs...done")
(magit-refresh))
(message "All wip-refs have a corresponding ref")))
;;; _
(provide 'magit-wip)
;;; magit-wip.el ends here

View File

@@ -17,15 +17,16 @@
;; Homepage: https://github.com/magit/magit
;; Keywords: git tools vc
;; Package-Version: 4.3.1
;; Package-Version: 20250621.2237
;; Package-Revision: a4f73fb2fb55
;; Package-Requires: (
;; (emacs "27.1")
;; (compat "30.0.2.0")
;; (llama "0.6.1")
;; (magit-section "4.3.1")
;; (compat "30.1")
;; (llama "0.6.3")
;; (magit-section "4.3.6")
;; (seq "2.24")
;; (transient "0.8.5")
;; (with-editor "3.4.3"))
;; (transient "0.9.0")
;; (with-editor "3.4.4"))
;; SPDX-License-Identifier: GPL-3.0-or-later
@@ -782,6 +783,7 @@ For X11 something like ~/.xinitrc should work.\n"
(require 'magit-gitignore)
(require 'magit-sparse-checkout)
(require 'magit-extras)
(require 'magit-dired)
(require 'git-rebase)
(require 'magit-bookmark)))

File diff suppressed because it is too large Load Diff