update packages
This commit is contained in:
@@ -31,6 +31,7 @@ All Contributors
|
||||
- Aaron Madlon-Kay
|
||||
- Abdo Roig-Maranges
|
||||
- Adam Benanti
|
||||
- Adam Jones
|
||||
- Adam Kruszewski
|
||||
- Adam Porter
|
||||
- Adam Spiers
|
||||
@@ -56,6 +57,7 @@ All Contributors
|
||||
- Andrew Kirkpatrick
|
||||
- Andrew Psaltis
|
||||
- Andrew Schwartzmeyer
|
||||
- Andrew Zipperer
|
||||
- Andrey Smirnov
|
||||
- Andriy Kmit'
|
||||
- Andy Sawyer
|
||||
@@ -151,6 +153,7 @@ All Contributors
|
||||
- Frédéric Giquel
|
||||
- Fritz Grabo
|
||||
- Fritz Stelzer
|
||||
- gemmaro
|
||||
- Geoff Shannon
|
||||
- George Kadianakis
|
||||
- Géza Herman
|
||||
@@ -169,16 +172,20 @@ All Contributors
|
||||
- Ian Eure
|
||||
- Ian Milligan
|
||||
- Ilya Grigoriev
|
||||
- Iñaki Arenaza
|
||||
- Ingmar Sittl
|
||||
- Ingo Lohmar
|
||||
- Ioan-Adrian Ratiu
|
||||
- Ivan Brennan
|
||||
- Jacob Ilsø
|
||||
- Jan Tatarik
|
||||
- Jasper St. Pierre
|
||||
- JD Smith
|
||||
- Jean-Louis Giordano
|
||||
- Jeff Bellegarde
|
||||
- Jeff Dairiki
|
||||
- Jeremy Meng
|
||||
- Jeremy Sowden
|
||||
- Jesse Alama
|
||||
- Jim Blandy
|
||||
- Joakim Jalap
|
||||
@@ -232,6 +239,7 @@ All Contributors
|
||||
- Louis Roché
|
||||
- Luís Oliveira
|
||||
- Luke Amdor
|
||||
- Magnar Sveen
|
||||
- Magnus Malm
|
||||
- Mak Kolybabi
|
||||
- Manuel Vázquez Acosta
|
||||
@@ -250,6 +258,7 @@ All Contributors
|
||||
- Markus Beppler
|
||||
- Martin Joerg
|
||||
- Martin Polden
|
||||
- Matt Beshara
|
||||
- Matthew Fluet
|
||||
- Matthew Kraai
|
||||
- Matthieu Hauglustaine
|
||||
@@ -277,18 +286,22 @@ All Contributors
|
||||
- Nicolas Dudebout
|
||||
- Nicolas Petton
|
||||
- Nicolas Richard
|
||||
- Nikita Leshenko
|
||||
- Nikolay Martynov
|
||||
- Noam Postavsky
|
||||
- N. Troy de Freitas
|
||||
- Ola x Nilsson
|
||||
- Ola Nilsson
|
||||
- Ole Arndt
|
||||
- Oleh Krehel
|
||||
- Orivej Desh
|
||||
- Óscar Fuentes
|
||||
- Pancho Horrillo
|
||||
- Park Zhou
|
||||
- Paul Pogonyshev
|
||||
- Paul Stadig
|
||||
- Pavel Holejsovsky
|
||||
- Pekka Pessi
|
||||
- Pengji Zhang
|
||||
- Peter Eisentraut
|
||||
- Peter Jaros
|
||||
- Peter J. Weisberg
|
||||
@@ -303,7 +316,9 @@ All Contributors
|
||||
- Phil Sainty
|
||||
- Pierre Neidhardt
|
||||
- Pieter Praet
|
||||
- Pieter van Oostrum
|
||||
- Prathamesh Sonpatki
|
||||
- Pratyush Yadav
|
||||
- Pritam Baral
|
||||
- rabio
|
||||
- Radon Rosborough
|
||||
@@ -320,6 +335,7 @@ All Contributors
|
||||
- Robin Green
|
||||
- Roey Darwish Dror
|
||||
- Roger Crew
|
||||
- Roland Marchand
|
||||
- Romain Francoise
|
||||
- Ron Parker
|
||||
- Roy Crihfield
|
||||
@@ -352,6 +368,7 @@ All Contributors
|
||||
- Steven Thomas
|
||||
- Steven Vancoillie
|
||||
- Steve Purcell
|
||||
- StrawberryTea
|
||||
- Suhail Shergill
|
||||
- Sylvain Rousseau
|
||||
- Syohei Yoshida
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Phil Jackson <phil@shellarchive.co.uk>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
(put 'git-rebase-kill-line :advertised-binding (kbd "k"))
|
||||
|
||||
(easy-menu-define git-rebase-mode-menu git-rebase-mode-map
|
||||
"Git-Rebase mode menu"
|
||||
"Git-Rebase mode menu."
|
||||
'("Rebase"
|
||||
["Pick" git-rebase-pick t]
|
||||
["Reword" git-rebase-reword t]
|
||||
@@ -375,13 +375,11 @@ non-nil, return the beginning and end of the current rebase line,
|
||||
if any."
|
||||
(cond
|
||||
((use-region-p)
|
||||
(let ((beg (save-excursion (goto-char (region-beginning))
|
||||
(line-beginning-position)))
|
||||
(end (save-excursion (goto-char (region-end))
|
||||
(line-end-position))))
|
||||
(when (and (git-rebase-line-p beg)
|
||||
(git-rebase-line-p end))
|
||||
(list beg (1+ end)))))
|
||||
(let ((beg (magit--bol-position (region-beginning)))
|
||||
(end (magit--eol-position (region-end))))
|
||||
(and (git-rebase-line-p beg)
|
||||
(git-rebase-line-p end)
|
||||
(list beg (1+ end)))))
|
||||
((and fallback (git-rebase-line-p))
|
||||
(list (line-beginning-position)
|
||||
(1+ (line-end-position))))))
|
||||
@@ -705,6 +703,7 @@ Rebase files are generated when you run \"git rebase -i\" or run
|
||||
`magit-interactive-rebase'. They describe how Git should perform
|
||||
the rebase. See the documentation for git-rebase (e.g., by
|
||||
running \"man git-rebase\" at the command line) for details."
|
||||
:interactive nil
|
||||
:group 'git-rebase
|
||||
(setq comment-start (or (magit-get "core.commentChar") "#"))
|
||||
(setq git-rebase-comment-re (concat "^" (regexp-quote comment-start)))
|
||||
@@ -718,8 +717,10 @@ running \"man git-rebase\" at the command line) for details."
|
||||
(when git-rebase-confirm-cancel
|
||||
(add-hook 'with-editor-cancel-query-functions
|
||||
#'git-rebase-cancel-confirm nil t))
|
||||
(setq-local redisplay-highlight-region-function #'git-rebase-highlight-region)
|
||||
(setq-local redisplay-unhighlight-region-function #'git-rebase-unhighlight-region)
|
||||
(setq-local redisplay-highlight-region-function
|
||||
#'git-rebase-highlight-region)
|
||||
(setq-local redisplay-unhighlight-region-function
|
||||
#'git-rebase-unhighlight-region)
|
||||
(add-hook 'with-editor-pre-cancel-hook #'git-rebase-autostash-save nil t)
|
||||
(add-hook 'with-editor-post-cancel-hook #'git-rebase-autostash-apply nil t)
|
||||
(setq imenu-prev-index-position-function
|
||||
@@ -775,7 +776,7 @@ running \"man git-rebase\" at the command line) for details."
|
||||
(git-rebase-match-comment-line 0 'font-lock-comment-face)
|
||||
("\\[[^[]*\\]"
|
||||
0 'magit-keyword t)
|
||||
("\\(?:fixup!\\|squash!\\)"
|
||||
("\\(?:fixup!\\|squash!\\|amend!\\)"
|
||||
0 'magit-keyword-squash t)
|
||||
(,(format "^%s Rebase \\([^ ]*\\) onto \\([^ ]*\\)" comment-start)
|
||||
(1 'git-rebase-comment-hash t)
|
||||
@@ -786,10 +787,10 @@ running \"man git-rebase\" at the command line) for details."
|
||||
(1 'git-rebase-label t))))
|
||||
|
||||
(defun git-rebase-mode-show-keybindings ()
|
||||
"Modify the \"Commands:\" section of the comment Git generates
|
||||
at the bottom of the file so that in place of the one-letter
|
||||
abbreviation for the command, it shows the command's keybinding.
|
||||
By default, this is the same except for the \"pick\" command."
|
||||
"Modify the \"Commands:\" section of the comment Git generates.
|
||||
Modify that section to replace Git's one-letter command abbreviation,
|
||||
with the key bindings used in Magit. By default, these are the same,
|
||||
except for the \"pick\" command."
|
||||
(let ((inhibit-read-only t))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-apply.el --- Apply Git diffs -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -49,11 +49,6 @@
|
||||
(path &optional prefer-short))
|
||||
(defvar borg-user-emacs-directory)
|
||||
|
||||
(cl-eval-when (compile load)
|
||||
(when (< emacs-major-version 26)
|
||||
(defalias 'smerge-keep-upper 'smerge-keep-mine)
|
||||
(defalias 'smerge-keep-lower 'smerge-keep-other)))
|
||||
|
||||
;;; Options
|
||||
|
||||
(defcustom magit-delete-by-moving-to-trash t
|
||||
@@ -192,10 +187,8 @@ adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
|
||||
(magit-apply-patch
|
||||
file args
|
||||
(concat (oref file header)
|
||||
(mapconcat #'identity
|
||||
(magit-apply--adjust-hunk-new-starts
|
||||
(mapcar #'magit-apply--section-content hunks))
|
||||
"")))))
|
||||
(string-join (magit-apply--adjust-hunk-new-starts
|
||||
(mapcar #'magit-apply--section-content hunks)))))))
|
||||
|
||||
(defun magit-apply-hunk (hunk &rest args)
|
||||
(let ((file (oref hunk parent)))
|
||||
@@ -224,7 +217,7 @@ adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
|
||||
(defun magit-apply-patch (section:s args patch)
|
||||
(let* ((files (if (atom section:s)
|
||||
(list (oref section:s value))
|
||||
(--map (oref it value) section:s)))
|
||||
(mapcar (##oref % value) section:s)))
|
||||
(command (symbol-name this-command))
|
||||
(command (if (and command (string-match "^magit-\\([^-]+\\)" command))
|
||||
(match-string 1 command)
|
||||
@@ -258,11 +251,12 @@ adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
|
||||
(defun magit-apply--get-diffs (sections)
|
||||
(magit-section-case
|
||||
([file diffstat]
|
||||
(--map (or (magit-get-section
|
||||
(append `((file . ,(oref it value)))
|
||||
(magit-section-ident magit-root-section)))
|
||||
(error "Cannot get required diff headers"))
|
||||
sections))
|
||||
(mapcar (lambda (section)
|
||||
(or (magit-get-section
|
||||
(append `((file . ,(oref section value)))
|
||||
(magit-section-ident magit-root-section)))
|
||||
(error "Cannot get required diff headers")))
|
||||
sections))
|
||||
(t sections)))
|
||||
|
||||
(defun magit-apply--ignore-whitespace-p (selection type scope)
|
||||
@@ -344,7 +338,7 @@ With prefix argument FORCE, offer ignored files for completion."
|
||||
;; For backward compatibility, and because of
|
||||
;; the function's name, don't require a list.
|
||||
(magit-stage-1 (and force "--force")
|
||||
(if (listp files) files (list files)))))
|
||||
(ensure-list files))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-stage-modified (&optional all)
|
||||
@@ -413,10 +407,10 @@ ignored) files."
|
||||
(magit-wip-commit-after-apply files " after stage")))
|
||||
|
||||
(defvar magit-post-stage-hook-commands
|
||||
'(magit-stage
|
||||
magit-stage-buffer-file
|
||||
magit-stage-file
|
||||
magit-stage-modified))
|
||||
(list #'magit-stage
|
||||
#'magit-stage-buffer-file
|
||||
#'magit-stage-file
|
||||
#'magit-stage-modified))
|
||||
|
||||
(defun magit-run-post-stage-hook ()
|
||||
(when (memq this-command magit-post-stage-hook-commands)
|
||||
@@ -472,7 +466,7 @@ ignored) files."
|
||||
(magit-with-toplevel
|
||||
;; For backward compatibility, and because of
|
||||
;; the function's name, don't require a list.
|
||||
(magit-unstage-1 (if (listp files) files (list files)))))
|
||||
(magit-unstage-1 (ensure-list files))))
|
||||
|
||||
(defun magit-unstage-1 (files)
|
||||
(magit-wip-commit-before-change files " before unstage")
|
||||
@@ -483,7 +477,7 @@ ignored) files."
|
||||
|
||||
(defun magit-unstage-intent (files)
|
||||
(if-let ((staged (magit-staged-files))
|
||||
(intent (--filter (member it staged) files)))
|
||||
(intent (seq-filter (##member % staged) files)))
|
||||
(magit-unstage-1 intent)
|
||||
(user-error "Already unstaged")))
|
||||
|
||||
@@ -501,10 +495,10 @@ ignored) files."
|
||||
(magit-wip-commit-after-apply nil " after unstage"))
|
||||
|
||||
(defvar magit-post-unstage-hook-commands
|
||||
'(magit-unstage
|
||||
magit-unstage-buffer-file
|
||||
magit-unstage-file
|
||||
magit-unstage-all))
|
||||
(list #'magit-unstage
|
||||
#'magit-unstage-buffer-file
|
||||
#'magit-unstage-file
|
||||
#'magit-unstage-all))
|
||||
|
||||
(defun magit-run-post-unstage-hook ()
|
||||
(when (memq this-command magit-post-unstage-hook-commands)
|
||||
@@ -555,9 +549,10 @@ of a side, then keep that side without prompting."
|
||||
(funcall apply section "--reverse" "--index"))))
|
||||
|
||||
(defun magit-discard-hunks (sections)
|
||||
(magit-confirm 'discard (format "Discard %s hunks from %s"
|
||||
(length sections)
|
||||
(magit-section-parent-value (car sections))))
|
||||
(magit-confirm 'discard
|
||||
(list "Discard %d hunks from %s"
|
||||
(length sections)
|
||||
(magit-section-parent-value (car sections))))
|
||||
(magit-discard-apply-n sections #'magit-apply-hunks))
|
||||
|
||||
(defun magit-discard-apply-n (sections apply)
|
||||
@@ -689,7 +684,7 @@ of a side, then keep that side without prompting."
|
||||
(magit-call-git "reset" "--" orig)))))
|
||||
|
||||
(defun magit-discard-files--discard (sections new-files)
|
||||
(let ((files (--map (oref it value) sections)))
|
||||
(let ((files (mapcar (##oref % value) sections)))
|
||||
(magit-confirm-files 'discard (append files new-files)
|
||||
(format "Discard %s changes in" (magit-diff-type)))
|
||||
(if (eq (magit-diff-type (car sections)) 'unstaged)
|
||||
@@ -700,15 +695,15 @@ of a side, then keep that side without prompting."
|
||||
(let ((binaries (magit-binary-files "--cached")))
|
||||
(when binaries
|
||||
(setq sections
|
||||
(--remove (member (oref it value) binaries)
|
||||
sections)))
|
||||
(seq-remove (##member (oref % value) binaries)
|
||||
sections)))
|
||||
(cond ((length= sections 1)
|
||||
(magit-discard-apply (car sections) 'magit-apply-diff))
|
||||
(sections
|
||||
(magit-discard-apply-n sections #'magit-apply-diffs)))
|
||||
(when binaries
|
||||
(let ((modified (magit-unstaged-files t)))
|
||||
(setq binaries (--separate (member it modified) binaries)))
|
||||
(setq binaries (magit--separate (##member % modified) binaries)))
|
||||
(when (cadr binaries)
|
||||
(magit-call-git "reset" "--" (cadr binaries)))
|
||||
(when (car binaries)
|
||||
@@ -745,9 +740,9 @@ so causes the change to be applied to the index as well."
|
||||
|
||||
(defun magit-reverse-hunks (sections args)
|
||||
(magit-confirm 'reverse
|
||||
(format "Reverse %s hunks from %s"
|
||||
(length sections)
|
||||
(magit-section-parent-value (car sections))))
|
||||
(list "Reverse %d hunks from %s"
|
||||
(length sections)
|
||||
(magit-section-parent-value (car sections))))
|
||||
(magit-reverse-apply sections #'magit-apply-hunks args))
|
||||
|
||||
(defun magit-reverse-file (section args)
|
||||
@@ -762,9 +757,9 @@ so causes the change to be applied to the index as well."
|
||||
magit-buffer-range)
|
||||
(t
|
||||
"--cached")))))
|
||||
(--separate (member (oref it value) bs)
|
||||
sections))))
|
||||
(magit-confirm-files 'reverse (--map (oref it value) sections))
|
||||
(magit--separate (##member (oref % value) bs)
|
||||
sections))))
|
||||
(magit-confirm-files 'reverse (mapcar (##oref % value) sections))
|
||||
(cond ((length= sections 1)
|
||||
(magit-reverse-apply (car sections) #'magit-apply-diff args))
|
||||
(sections
|
||||
@@ -789,7 +784,7 @@ a separate commit. A typical workflow would be:
|
||||
1. Visit the `HEAD' commit and navigate to the change that should
|
||||
not have been included in that commit.
|
||||
2. Type \"u\" (`magit-unstage') to reverse it in the index.
|
||||
This assumes that `magit-unstage-committed-changes' is non-nil.
|
||||
This assumes that `magit-unstage-committed' is non-nil.
|
||||
3. Type \"c e\" to extend `HEAD' with the staged changes,
|
||||
including those that were already staged before.
|
||||
4. Optionally stage the remaining changes using \"s\" or \"S\"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-autorevert.el --- Revert buffers when files in repository change -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -20,9 +20,16 @@
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with Magit. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This library implements support for automatically reverting buffers
|
||||
;; when visited files in the repository change.
|
||||
|
||||
;; See (info "(magit)Automatic Reverting of File-Visiting Buffers").
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'magit-git)
|
||||
(require 'magit-process)
|
||||
|
||||
(require 'autorevert)
|
||||
|
||||
@@ -58,9 +65,9 @@ is enabled."
|
||||
:group 'auto-revert
|
||||
:group 'magit-auto-revert
|
||||
:group 'magit-related
|
||||
:type '(radio (const :tag "No filter" nil)
|
||||
(function-item magit-auto-revert-buffer-p)
|
||||
(function-item magit-auto-revert-repository-buffer-p)
|
||||
:type `(radio (const :tag "No filter" nil)
|
||||
(function-item ,#'magit-auto-revert-buffer-p)
|
||||
(function-item ,#'magit-auto-revert-repository-buffer-p)
|
||||
function))
|
||||
|
||||
(defcustom magit-auto-revert-tracked-only t
|
||||
@@ -98,19 +105,21 @@ seconds of user inactivity. That is not desirable."
|
||||
;;; Mode
|
||||
|
||||
(defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
|
||||
(if file
|
||||
(when-let ((buffer (find-buffer-visiting file)))
|
||||
(with-current-buffer buffer
|
||||
(magit-turn-on-auto-revert-mode-if-desired)))
|
||||
(when (and (not auto-revert-mode) ; see #3014
|
||||
(not global-auto-revert-mode) ; see #3460
|
||||
buffer-file-name
|
||||
(file-readable-p buffer-file-name)
|
||||
(compat-call executable-find (magit-git-executable) t)
|
||||
(magit-toplevel)
|
||||
(or (not magit-auto-revert-tracked-only)
|
||||
(magit-file-tracked-p buffer-file-name)))
|
||||
(auto-revert-mode 1))))
|
||||
(cond (file
|
||||
(when-let ((buffer (find-buffer-visiting file)))
|
||||
(with-current-buffer buffer
|
||||
(magit-turn-on-auto-revert-mode-if-desired))))
|
||||
((and (not auto-revert-mode) ; see #3014
|
||||
(not global-auto-revert-mode) ; see #3460
|
||||
buffer-file-name
|
||||
(or auto-revert-remote-files ; see #5422
|
||||
(not (file-remote-p buffer-file-name)))
|
||||
(file-readable-p buffer-file-name)
|
||||
(compat-call executable-find (magit-git-executable) t)
|
||||
(magit-toplevel)
|
||||
(or (not magit-auto-revert-tracked-only)
|
||||
(magit-file-tracked-p buffer-file-name)))
|
||||
(auto-revert-mode 1))))
|
||||
|
||||
;;;###autoload
|
||||
(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
|
||||
@@ -152,7 +161,7 @@ and code surrounding the definition of this function."
|
||||
(magit-auto-revert-mode 1)
|
||||
(magit-message
|
||||
"Turning on magit-auto-revert-mode...done%s"
|
||||
(let ((elapsed (float-time (time-subtract nil start))))
|
||||
(let ((elapsed (float-time (time-since start))))
|
||||
(if (> elapsed 0.2)
|
||||
(format " (%.3fs, %s buffers checked)" elapsed
|
||||
(length (buffer-list)))
|
||||
@@ -244,7 +253,7 @@ defaults to nil) for any BUFFER."
|
||||
;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
|
||||
(file-in-directory-p dir top))))))
|
||||
|
||||
(defun auto-revert-buffers--buffer-list-filter (fn)
|
||||
(define-advice auto-revert-buffers (:around (fn) buffer-list-filter)
|
||||
(cl-incf magit-auto-revert-counter)
|
||||
(if (or global-auto-revert-mode
|
||||
(not auto-revert-buffer-list)
|
||||
@@ -257,9 +266,6 @@ defaults to nil) for any BUFFER."
|
||||
(unless auto-revert-timer
|
||||
(auto-revert-set-timer))))
|
||||
|
||||
(advice-add 'auto-revert-buffers :around
|
||||
#'auto-revert-buffers--buffer-list-filter)
|
||||
|
||||
;;; _
|
||||
(provide 'magit-autorevert)
|
||||
;;; magit-autorevert.el ends here
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-base.el --- Early birds -*- lexical-binding:t; coding:utf-8 -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -32,20 +32,21 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defconst magit--minimal-git "2.2.0")
|
||||
(defconst magit--minimal-emacs "25.1")
|
||||
;; Also update EMACS_VERSION in "default.mk".
|
||||
(defconst magit--minimal-emacs "27.1")
|
||||
(defconst magit--minimal-git "2.25.0")
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'compat)
|
||||
(require 'dash)
|
||||
(require 'eieio)
|
||||
(require 'llama)
|
||||
(require 'subr-x)
|
||||
|
||||
;; For older Emacs releases we depend on an updated `seq' release from
|
||||
;; GNU ELPA, for `seq-keep'. Unfortunately something else may already
|
||||
;; have required `seq', before `package' had a chance to put the more
|
||||
;; recent version earlier on the `load-path'.
|
||||
(when (and (featurep' seq)
|
||||
(when (and (featurep 'seq)
|
||||
(not (fboundp 'seq-keep)))
|
||||
(unload-feature 'seq 'force))
|
||||
(require 'seq)
|
||||
@@ -54,7 +55,7 @@
|
||||
|
||||
(require 'magit-section)
|
||||
|
||||
(eval-when-compile (require 'ido))
|
||||
(eval-when-compile (require 'info))
|
||||
(declare-function Info-get-token "info" (pos start all &optional errorstring))
|
||||
|
||||
(eval-when-compile (require 'vc-git))
|
||||
@@ -81,13 +82,14 @@ option to use `ivy-completing-read' or
|
||||
`ivy-completing-read', note that the items may always be shown in
|
||||
alphabetical order, depending on your version of Ivy."
|
||||
:group 'magit-essentials
|
||||
:type '(radio (function-item magit-builtin-completing-read)
|
||||
(function-item magit-ido-completing-read)
|
||||
: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")))
|
||||
|
||||
(defcustom magit-dwim-selection
|
||||
;; Do not function-quote to avoid circular dependencies.
|
||||
'((magit-stash-apply nil t)
|
||||
(magit-ediff-resolve-all nil t)
|
||||
(magit-ediff-resolve-rest nil t)
|
||||
@@ -144,6 +146,8 @@ The value has the form ((COMMAND nil|PROMPT DEFAULT)...).
|
||||
(const untrack)
|
||||
(const rename)
|
||||
(const reset-bisect)
|
||||
(const abort-cherry-pick)
|
||||
(const abort-revert)
|
||||
(const abort-rebase)
|
||||
(const abort-merge)
|
||||
(const merge-dirty)
|
||||
@@ -211,6 +215,13 @@ Sequences:
|
||||
`reset-bisect' Aborting (known to Git as \"resetting\") a
|
||||
bisect operation loses all information collected so far.
|
||||
|
||||
`abort-cherry-pick' Aborting a cherry-pick throws away all
|
||||
conflict resolutions which has already been carried out by the
|
||||
user.
|
||||
|
||||
`abort-revert' Aborting a revert throws away all conflict
|
||||
resolutions which has already been carried out by the user.
|
||||
|
||||
`abort-rebase' Aborting a rebase throws away all already
|
||||
modified commits, but it's possible to restore those from the
|
||||
reflog.
|
||||
@@ -318,7 +329,7 @@ Various:
|
||||
Global settings:
|
||||
|
||||
Instead of adding all of the above symbols to the value of this
|
||||
option you can also set it to the atom `t', which has the same
|
||||
option you can also set it to the atom t, which has the same
|
||||
effect as adding all of the above symbols. Doing that most
|
||||
certainly is a bad idea, especially because other symbols might
|
||||
be added in the future. So even if you don't want to be asked
|
||||
@@ -462,36 +473,41 @@ and delay of your graphical environment or operating system."
|
||||
|
||||
;;; Section Classes
|
||||
|
||||
(defclass magit-commit-section (magit-section) ())
|
||||
(defclass magit-commit-section (magit-section)
|
||||
((keymap :initform 'magit-commit-section-map)))
|
||||
|
||||
(setf (alist-get 'commit magit--section-type-alist) 'magit-commit-section)
|
||||
|
||||
(defclass magit-diff-section (magit-section) () :abstract t)
|
||||
(defclass magit-diff-section (magit-section)
|
||||
((keymap :initform 'magit-diff-section-map))
|
||||
:abstract t)
|
||||
|
||||
(defclass magit-file-section (magit-diff-section)
|
||||
((keymap :initform 'magit-file-section-map)
|
||||
(source :initform nil)
|
||||
(header :initform nil)
|
||||
(binary :initform nil)))
|
||||
(source :initform nil :initarg :source)
|
||||
(header :initform nil :initarg :header)
|
||||
(binary :initform nil :initarg :binary)))
|
||||
|
||||
(defclass magit-module-section (magit-file-section)
|
||||
((keymap :initform 'magit-module-section-map)
|
||||
(range :initform nil)))
|
||||
(range :initform nil :initarg :range)))
|
||||
|
||||
(defclass magit-hunk-section (magit-diff-section)
|
||||
((keymap :initform 'magit-hunk-section-map)
|
||||
(refined :initform nil)
|
||||
(combined :initform nil)
|
||||
(from-range :initform nil)
|
||||
(combined :initform nil :initarg :combined)
|
||||
(from-range :initform nil :initarg :from-range)
|
||||
(from-ranges :initform nil)
|
||||
(to-range :initform nil)
|
||||
(about :initform nil)))
|
||||
(to-range :initform nil :initarg :to-range)
|
||||
(about :initform nil :initarg :about)))
|
||||
|
||||
(setf (alist-get 'file magit--section-type-alist) 'magit-file-section)
|
||||
(setf (alist-get 'module magit--section-type-alist) 'magit-module-section)
|
||||
(setf (alist-get 'hunk magit--section-type-alist) 'magit-hunk-section)
|
||||
|
||||
(defclass magit-log-section (magit-section) () :abstract t)
|
||||
(defclass magit-log-section (magit-section)
|
||||
((keymap :initform 'magit-log-section-map))
|
||||
:abstract t)
|
||||
(defclass magit-unpulled-section (magit-log-section) ())
|
||||
(defclass magit-unpushed-section (magit-log-section) ())
|
||||
(defclass magit-unmerged-section (magit-log-section) ())
|
||||
@@ -506,9 +522,29 @@ and delay of your graphical environment or operating system."
|
||||
(defvar helm-crm-default-separator)
|
||||
(defvar ivy-sort-functions-alist)
|
||||
(defvar ivy-sort-matches-functions-alist)
|
||||
(defvar vertico-sort-function)
|
||||
|
||||
(defvar magit-completing-read--silent-default nil)
|
||||
|
||||
(defvar magit-completing-read-default-prompt-predicate
|
||||
(lambda ()
|
||||
(and (eq magit-completing-read-function
|
||||
'magit-builtin-completing-read)
|
||||
(not (or (bound-and-true-p helm-mode)
|
||||
(bound-and-true-p ivy-mode)
|
||||
(bound-and-true-p selectrum-mode)
|
||||
(bound-and-true-p vertico-mode)))))
|
||||
"Function used to determine whether to add default to prompt.
|
||||
|
||||
This is used by `magit-completing-read' (which see).
|
||||
|
||||
The default function returns nil, when a completion frameworks is used
|
||||
for which this is undesirable. More precisely, it returns nil, when
|
||||
`magit-completing-read-function' is not `magit-builtin-completing-read',
|
||||
or one of `helm-mode', `ivy-mode', `selectrum-mode' or `vertico-mode'
|
||||
is enabled. When this function returns nil, then nil is passed to
|
||||
`format-prompt' (which see), instead of the default (DEF or FALLBACK).")
|
||||
|
||||
(defun magit-completing-read ( prompt collection &optional
|
||||
predicate require-match initial-input
|
||||
hist def fallback)
|
||||
@@ -548,13 +584,11 @@ acts similarly to `completing-read', except for the following:
|
||||
is not, then this function always asks the user to choose a
|
||||
candidate, just as if both defaults were nil.
|
||||
|
||||
- \": \" is appended to PROMPT.
|
||||
|
||||
- PROMPT is modified to end with \" (default DEF|FALLBACK): \"
|
||||
provided that DEF or FALLBACK is non-nil, that neither
|
||||
`ivy-mode' nor `helm-mode' is enabled, and that
|
||||
`magit-completing-read-function' is set to its default value of
|
||||
`magit-builtin-completing-read'."
|
||||
- `format-prompt' is called on PROMPT and DEF (or FALLBACK if
|
||||
DEF is nil). This appends \": \" to the prompt and may also
|
||||
add the default to the prompt, using the format specified by
|
||||
`minibuffer-default-prompt-format' and depending on
|
||||
`magit-completing-read-default-prompt-predicate'."
|
||||
(setq magit-completing-read--silent-default nil)
|
||||
(if-let ((dwim (and def
|
||||
(nth 2 (seq-find (pcase-lambda (`(,cmd ,re ,_))
|
||||
@@ -571,13 +605,16 @@ acts similarly to `completing-read', except for the following:
|
||||
(unless def
|
||||
(setq def fallback))
|
||||
(let ((command this-command)
|
||||
(reply (funcall magit-completing-read-function
|
||||
(concat prompt ": ")
|
||||
(if (and 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)
|
||||
(if (and (not (functionp collection))
|
||||
def
|
||||
(not (member def collection)))
|
||||
(cons def collection)
|
||||
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 "")
|
||||
@@ -586,6 +623,13 @@ acts similarly to `completing-read', except for the following:
|
||||
nil)
|
||||
reply))))
|
||||
|
||||
(defun magit--format-prompt (prompt default)
|
||||
(format-prompt (if (string-suffix-p ": " prompt)
|
||||
(substring prompt 0 -2)
|
||||
prompt)
|
||||
(and (funcall magit-completing-read-default-prompt-predicate)
|
||||
default)))
|
||||
|
||||
(defun magit--completion-table (collection)
|
||||
(lambda (string pred action)
|
||||
(if (eq action 'metadata)
|
||||
@@ -595,22 +639,14 @@ acts similarly to `completing-read', except for the following:
|
||||
(defun magit-builtin-completing-read
|
||||
(prompt choices &optional predicate require-match initial-input hist def)
|
||||
"Magit wrapper for standard `completing-read' function."
|
||||
(unless (or (bound-and-true-p helm-mode)
|
||||
(bound-and-true-p ivy-mode)
|
||||
(bound-and-true-p vertico-mode)
|
||||
(bound-and-true-p selectrum-mode))
|
||||
(setq prompt (magit-prompt-with-default prompt def)))
|
||||
(unless (or (bound-and-true-p helm-mode)
|
||||
(bound-and-true-p ivy-mode))
|
||||
(setq choices (magit--completion-table choices)))
|
||||
(cl-letf (((symbol-function #'completion-pcm--all-completions)))
|
||||
(when (< emacs-major-version 26)
|
||||
(fset 'completion-pcm--all-completions
|
||||
'magit-completion-pcm--all-completions))
|
||||
(let ((ivy-sort-functions-alist nil))
|
||||
(completing-read prompt choices
|
||||
predicate require-match
|
||||
initial-input hist def))))
|
||||
(let ((ivy-sort-functions-alist nil)
|
||||
(vertico-sort-function nil))
|
||||
(completing-read prompt choices
|
||||
predicate require-match
|
||||
initial-input hist def)))
|
||||
|
||||
(define-obsolete-function-alias 'magit-completing-read-multiple*
|
||||
'magit-completing-read-multiple "Magit-Section 4.0.0")
|
||||
@@ -640,12 +676,6 @@ third-party completion frameworks."
|
||||
(equal omit-nulls t))
|
||||
(setq input string))
|
||||
(funcall split-string string separators omit-nulls trim)))
|
||||
;; In Emacs 25 this function has a bug, so we use a copy of the
|
||||
;; version from Emacs 26. bef9c7aa3
|
||||
((symbol-function #'completion-pcm--all-completions)
|
||||
(if (< emacs-major-version 26)
|
||||
'magit-completion-pcm--all-completions
|
||||
(symbol-function #'completion-pcm--all-completions)))
|
||||
;; Prevent `BUILT-IN' completion from messing up our existing
|
||||
;; order of the completion candidates. aa5f098ab
|
||||
(table (magit--completion-table table))
|
||||
@@ -660,7 +690,8 @@ third-party completion frameworks."
|
||||
(if no-split nil (bound-and-true-p helm-crm-default-separator)))
|
||||
;; And now, the moment we have all been waiting for...
|
||||
(values (completing-read-multiple
|
||||
prompt table predicate require-match initial-input
|
||||
(magit--format-prompt prompt def)
|
||||
table predicate require-match initial-input
|
||||
hist def inherit-input-method)))
|
||||
(if no-split input values)))
|
||||
|
||||
@@ -685,12 +716,6 @@ back to built-in `completing-read' for now." :error)
|
||||
(magit-builtin-completing-read prompt choices predicate require-match
|
||||
initial-input hist def)))
|
||||
|
||||
(defun magit-prompt-with-default (prompt def)
|
||||
(if (and def (length> prompt 2)
|
||||
(string-equal ": " (substring prompt -2)))
|
||||
(format "%s (default %s): " (substring prompt 0 -2) def)
|
||||
prompt))
|
||||
|
||||
(defvar-keymap magit-minibuffer-local-ns-map
|
||||
:parent minibuffer-local-map
|
||||
"SPC" #'magit-whitespace-disallowed
|
||||
@@ -713,7 +738,7 @@ This is similar to `read-string', but
|
||||
which case that is returned,
|
||||
* whitespace is not allowed and leading and trailing whitespace is
|
||||
removed automatically if NO-WHITESPACE is non-nil,
|
||||
* \": \" is appended to PROMPT, and
|
||||
* `format-prompt' is used internally.
|
||||
* an invalid DEFAULT-VALUE is silently ignored."
|
||||
(when default-value
|
||||
(when (consp default-value)
|
||||
@@ -722,7 +747,7 @@ This is similar to `read-string', but
|
||||
(setq default-value nil)))
|
||||
(let* ((minibuffer-completion-table nil)
|
||||
(val (read-from-minibuffer
|
||||
(magit-prompt-with-default (concat prompt ": ") default-value)
|
||||
(format-prompt prompt default-value)
|
||||
initial-input (and no-whitespace magit-minibuffer-local-ns-map)
|
||||
nil history default-value inherit-input-method))
|
||||
(trim (lambda (regexp string)
|
||||
@@ -754,10 +779,10 @@ This is similar to `read-string', but
|
||||
(let ((parts (nconc (list ,@(mapcar #'cadr clauses))
|
||||
,(and verbose '(list "[C-g] to abort")))))
|
||||
(concat ,prompt
|
||||
(mapconcat #'identity (butlast parts) ", ")
|
||||
(string-join (butlast parts) ", ")
|
||||
", or " (car (last parts)) " "))
|
||||
',(mapcar #'car clauses))
|
||||
,@(--map `(,(car it) ,@(cddr it)) clauses))
|
||||
,@(mapcar (##`(,(car %) ,@(cddr %))) clauses))
|
||||
(message "")))
|
||||
|
||||
(defun magit-y-or-n-p (prompt &optional action)
|
||||
@@ -776,6 +801,16 @@ ACTION is a member of option `magit-slow-confirm'."
|
||||
(cl-defun magit-confirm ( action &optional prompt prompt-n noabort
|
||||
(items nil sitems) prompt-suffix)
|
||||
(declare (indent defun))
|
||||
(when (and prompt (listp prompt))
|
||||
(setq prompt
|
||||
(apply #'format (car prompt)
|
||||
(mapcar (lambda (a) (if (stringp a) (string-replace "%" "%%" a) a))
|
||||
(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))
|
||||
(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))
|
||||
"? ")
|
||||
@@ -798,7 +833,7 @@ ACTION is a member of option `magit-slow-confirm'."
|
||||
((length= items 1)
|
||||
(and (magit-y-or-n-p prompt action) items))
|
||||
((length> items 1)
|
||||
(and (magit-y-or-n-p (concat (mapconcat #'identity items "\n")
|
||||
(and (magit-y-or-n-p (concat (string-join items "\n")
|
||||
"\n\n" prompt-n)
|
||||
action)
|
||||
items)))
|
||||
@@ -838,30 +873,25 @@ See info node `(magit)Debugging Tools' for more information."
|
||||
#'shell-quote-argument
|
||||
`(,(concat invocation-directory invocation-name)
|
||||
"-Q" "--eval" "(setq debug-on-error t)"
|
||||
,@(cl-mapcan
|
||||
,@(mapcan
|
||||
(lambda (dir) (list "-L" dir))
|
||||
(delete-dups
|
||||
(cl-mapcan
|
||||
(mapcan
|
||||
(lambda (lib)
|
||||
(let ((path (locate-library lib)))
|
||||
(cond
|
||||
(path
|
||||
(list (file-name-directory path)))
|
||||
((not (equal lib "libgit"))
|
||||
(error "Cannot find mandatory dependency %s" lib)))))
|
||||
(if-let ((path (locate-library lib)))
|
||||
(list (file-name-directory path))
|
||||
(error "Cannot find mandatory dependency %s" lib)))
|
||||
'(;; Like `LOAD_PATH' in `default.mk'.
|
||||
"compat"
|
||||
"dash"
|
||||
"libgit"
|
||||
"llama"
|
||||
"seq"
|
||||
"transient"
|
||||
"with-editor"
|
||||
;; Obviously `magit' itself is needed too.
|
||||
"magit"
|
||||
;; While these are part of the Magit repository,
|
||||
;; they are distributed as separate packages.
|
||||
"magit-section"
|
||||
"git-commit"
|
||||
))))
|
||||
;; While this is part of the Magit repository,
|
||||
;; it is distributed as a separate package.
|
||||
"magit-section"))))
|
||||
;; Avoid Emacs bug#16406 by using full path.
|
||||
"-l" ,(file-name-sans-extension (locate-library "magit")))
|
||||
" ")))
|
||||
@@ -882,11 +912,11 @@ as STRING."
|
||||
(i 0))
|
||||
`(let ((,s ,string))
|
||||
(let ,(save-match-data
|
||||
(cl-mapcan (lambda (sym)
|
||||
(cl-incf i)
|
||||
(and (not (eq (aref (symbol-name sym) 0) ?_))
|
||||
(list (list sym (list 'match-string i s)))))
|
||||
varlist))
|
||||
(mapcan (lambda (sym)
|
||||
(cl-incf i)
|
||||
(and (not (eq (aref (symbol-name sym) 0) ?_))
|
||||
(list (list sym (list 'match-string i s)))))
|
||||
varlist))
|
||||
,@body))))
|
||||
|
||||
(defun magit-delete-line ()
|
||||
@@ -901,26 +931,23 @@ If optional NUM is specified, only delete that subexpression."
|
||||
|
||||
(defun magit-file-line (file)
|
||||
"Return the first line of FILE as a string."
|
||||
(when (file-regular-p file)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(buffer-substring-no-properties (point-min)
|
||||
(line-end-position)))))
|
||||
(and (file-regular-p file)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(buffer-substring-no-properties (point-min)
|
||||
(line-end-position)))))
|
||||
|
||||
(defun magit-file-lines (file &optional keep-empty-lines)
|
||||
"Return a list of strings containing one element per line in FILE.
|
||||
Unless optional argument KEEP-EMPTY-LINES is t, trim all empty lines."
|
||||
(when (file-regular-p file)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(split-string (buffer-string) "\n" (not keep-empty-lines)))))
|
||||
(and (file-regular-p file)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(split-string (buffer-string) "\n" (not keep-empty-lines)))))
|
||||
|
||||
(defun magit-set-header-line-format (string)
|
||||
"Set the header-line using STRING.
|
||||
Propertize STRING with the `magit-header-line'. If the `face'
|
||||
property of any part of STRING is already set, then that takes
|
||||
precedence. Also pad the left side of STRING so that it aligns
|
||||
with the text area."
|
||||
"Set `header-line-format' in the current buffer based on STRING.
|
||||
Pad the left side of STRING so that it aligns with the text area."
|
||||
(setq header-line-format
|
||||
(concat (propertize " " 'display '(space :align-to 0))
|
||||
string)))
|
||||
@@ -993,6 +1020,16 @@ one trailing newline is added."
|
||||
(and (eq trim ?\n) "\n"))
|
||||
str)))
|
||||
|
||||
(defun magit--separate (pred list)
|
||||
"Separate elements of LIST that do and don't satisfy PRED.
|
||||
Return a list of two lists; the first containing the elements that
|
||||
do satisfy PRED and the second containing the elements that don't."
|
||||
(let (y n)
|
||||
(dolist (elt list)
|
||||
(push elt (if (funcall pred elt) y n)))
|
||||
(list (nreverse y)
|
||||
(nreverse n))))
|
||||
|
||||
(defun magit--version> (v1 v2)
|
||||
"Return t if version V1 is higher (younger) than V2.
|
||||
This function should be named `version>' and be part of Emacs."
|
||||
@@ -1005,77 +1042,6 @@ This function should be named `version>=' and be part of Emacs."
|
||||
|
||||
;;; Kludges for Emacs Bugs
|
||||
|
||||
(defun magit-file-accessible-directory-p (filename)
|
||||
"Like `file-accessible-directory-p' but work around an Apple bug.
|
||||
See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=21573#17
|
||||
and https://github.com/magit/magit/issues/2295."
|
||||
(and (file-directory-p filename)
|
||||
(file-accessible-directory-p filename)))
|
||||
|
||||
(when (< emacs-major-version 27)
|
||||
;; Work around https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559.
|
||||
;; Fixed by cb55ccae8be946f1562d74718086a4c8c8308ee5 in Emacs 27.1.
|
||||
(with-eval-after-load 'vc-git
|
||||
(defun vc-git-conflicted-files (directory)
|
||||
"Return the list of files with conflicts in DIRECTORY."
|
||||
(let* ((status
|
||||
(vc-git--run-command-string directory "diff-files"
|
||||
"--name-status"))
|
||||
(lines (when status (split-string status "\n" 'omit-nulls)))
|
||||
files)
|
||||
(dolist (line lines files)
|
||||
(when (string-match "\\([ MADRCU?!]\\)[ \t]+\\(.+\\)" line)
|
||||
(let ((state (match-string 1 line))
|
||||
(file (match-string 2 line)))
|
||||
(when (equal state "U")
|
||||
(push (expand-file-name file directory) files)))))))))
|
||||
|
||||
(when (< emacs-major-version 27)
|
||||
(defun vc-git--call@bug21559 (fn buffer command &rest args)
|
||||
"Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
|
||||
(let ((process-environment process-environment))
|
||||
(when revert-buffer-in-progress-p
|
||||
(push "GIT_OPTIONAL_LOCKS=0" process-environment))
|
||||
(apply fn buffer command args)))
|
||||
(advice-add 'vc-git--call :around 'vc-git--call@bug21559)
|
||||
|
||||
(defun vc-git-command@bug21559
|
||||
(fn buffer okstatus file-or-list &rest flags)
|
||||
"Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
|
||||
(let ((process-environment process-environment))
|
||||
(when revert-buffer-in-progress-p
|
||||
(push "GIT_OPTIONAL_LOCKS=0" process-environment))
|
||||
(apply fn buffer okstatus file-or-list flags)))
|
||||
(advice-add 'vc-git-command :around 'vc-git-command@bug21559)
|
||||
|
||||
(defun auto-revert-handler@bug21559 (fn)
|
||||
"Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
|
||||
(let ((revert-buffer-in-progress-p t))
|
||||
(funcall fn)))
|
||||
(advice-add 'auto-revert-handler :around 'auto-revert-handler@bug21559)
|
||||
)
|
||||
|
||||
(when (< emacs-major-version 26)
|
||||
;; In Emacs 25 `completion-pcm--all-completions' reverses the
|
||||
;; completion list. This is the version from Emacs 26, which
|
||||
;; fixes that issue. bug#24676
|
||||
(defun magit-completion-pcm--all-completions (prefix pattern table pred)
|
||||
(if (completion-pcm--pattern-trivial-p pattern)
|
||||
(all-completions (concat prefix (car pattern)) table pred)
|
||||
(let* ((regex (completion-pcm--pattern->regex pattern))
|
||||
(case-fold-search completion-ignore-case)
|
||||
(completion-regexp-list (cons regex completion-regexp-list))
|
||||
(compl (all-completions
|
||||
(concat prefix
|
||||
(if (stringp (car pattern)) (car pattern) ""))
|
||||
table pred)))
|
||||
(if (not (functionp table))
|
||||
compl
|
||||
(let ((poss ()))
|
||||
(dolist (c compl)
|
||||
(when (string-match-p regex c) (push c poss)))
|
||||
(nreverse poss)))))))
|
||||
|
||||
(defun magit-which-function ()
|
||||
"Return current function name based on point.
|
||||
|
||||
@@ -1134,7 +1100,7 @@ the value in the symbol's `saved-value' property if any, or
|
||||
;;; Kludges for Info Manuals
|
||||
|
||||
;;;###autoload
|
||||
(defun Info-follow-nearest-node--magit-gitman (fn &optional fork)
|
||||
(define-advice Info-follow-nearest-node (:around (fn &optional fork) gitman)
|
||||
(let ((node (Info-get-token
|
||||
(point) "\\*note[ \n\t]+"
|
||||
"\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
|
||||
@@ -1145,19 +1111,12 @@ the value in the symbol's `saved-value' property if any, or
|
||||
(man (match-string 1 node)))
|
||||
('woman (require 'woman)
|
||||
(woman (match-string 1 node)))
|
||||
(_
|
||||
(user-error "Invalid value for `magit-view-git-manual-method'")))
|
||||
(_ (user-error "Invalid value for `magit-view-git-manual-method'")))
|
||||
(funcall fn fork))))
|
||||
|
||||
;;;###autoload
|
||||
(advice-add 'Info-follow-nearest-node :around
|
||||
#'Info-follow-nearest-node--magit-gitman)
|
||||
|
||||
;; When making changes here, then also adjust the copy in docs/Makefile.
|
||||
;;;###autoload
|
||||
(advice-add 'org-man-export :around #'org-man-export--magit-gitman)
|
||||
;;;###autoload
|
||||
(defun org-man-export--magit-gitman (fn link description format)
|
||||
(define-advice org-man-export (:around (fn link description format) gitman)
|
||||
(if (and (eq format 'texinfo)
|
||||
(string-prefix-p "git" link))
|
||||
(string-replace "%s" link "
|
||||
@@ -1177,47 +1136,31 @@ the %s(1) manpage.
|
||||
|
||||
;;; Kludges for Package Managers
|
||||
|
||||
(defun magit--straight-chase-links (filename)
|
||||
(defun magit--chase-links (filename)
|
||||
"Chase links in FILENAME until a name that is not a link.
|
||||
|
||||
This is the same as `file-chase-links', except that it also
|
||||
handles fake symlinks that are created by the package manager
|
||||
straight.el on Windows.
|
||||
This is the same as `file-chase-links', except that it also handles
|
||||
fake symlinks that are created by some source based package managers
|
||||
\(Elpaca and Straight) on Windows.
|
||||
|
||||
See <https://github.com/raxod502/straight.el/issues/520>."
|
||||
(when (and (bound-and-true-p straight-symlink-emulation-mode)
|
||||
(fboundp 'straight-chase-emulated-symlink))
|
||||
(when-let ((target (straight-chase-emulated-symlink filename)))
|
||||
(unless (eq target 'broken)
|
||||
(setq filename target))))
|
||||
(when-let*
|
||||
((manager (cond ((bound-and-true-p straight-symlink-mode) 'straight)
|
||||
((bound-and-true-p elpaca-no-symlink-mode) 'elpaca)))
|
||||
(build (pcase manager
|
||||
('straight (bound-and-true-p straight-build-dir))
|
||||
('elpaca (bound-and-true-p elpaca-builds-directory))))
|
||||
((string-prefix-p build filename))
|
||||
(repo (pcase manager
|
||||
('straight
|
||||
(and (bound-and-true-p straight-base-dir)
|
||||
(expand-file-name "repos/magit/lisp/" straight-base-dir)))
|
||||
('elpaca
|
||||
(and (bound-and-true-p elpaca-repos-directory)
|
||||
(expand-file-name "magit/lisp/" elpaca-repos-directory))))))
|
||||
(setq filename (expand-file-name (file-name-nondirectory filename) repo)))
|
||||
(file-chase-links filename))
|
||||
|
||||
;;; Kludges for older Emacs versions
|
||||
|
||||
(if (fboundp 'with-connection-local-variables)
|
||||
(defalias 'magit--with-connection-local-variables
|
||||
#'with-connection-local-variables)
|
||||
(defmacro magit--with-connection-local-variables (&rest body)
|
||||
"Abridged `with-connection-local-variables' for pre Emacs 27 compatibility.
|
||||
Bind shell file name and switch for remote execution.
|
||||
`with-connection-local-variables' isn't available until Emacs 27.
|
||||
This kludge provides the minimal functionality required by
|
||||
Magit."
|
||||
`(if (file-remote-p default-directory)
|
||||
(pcase-let ((`(,shell-file-name ,shell-command-switch)
|
||||
(with-no-warnings ; about unknown tramp functions
|
||||
(require 'tramp)
|
||||
(let ((vec (tramp-dissect-file-name
|
||||
default-directory)))
|
||||
(list (tramp-get-method-parameter
|
||||
vec 'tramp-remote-shell)
|
||||
(mapconcat #'identity
|
||||
(tramp-get-method-parameter
|
||||
vec 'tramp-remote-shell-args)
|
||||
" "))))))
|
||||
,@body)
|
||||
,@body)))
|
||||
|
||||
;;; Miscellaneous
|
||||
|
||||
(defun magit-message (format-string &rest args)
|
||||
@@ -1225,7 +1168,7 @@ Magit."
|
||||
Like `message', except that if the users configured option
|
||||
`magit-no-message' to prevent the message corresponding to
|
||||
FORMAT-STRING to be displayed, then don't."
|
||||
(unless (--first (string-prefix-p it format-string) magit-no-message)
|
||||
(unless (seq-find (##string-prefix-p % format-string) magit-no-message)
|
||||
(apply #'message format-string args)))
|
||||
|
||||
(defun magit-msg (format-string &rest args)
|
||||
@@ -1259,6 +1202,16 @@ Like `message', except that `message-log-max' is bound to nil."
|
||||
ellipsis)))
|
||||
(user-error "Variable magit-ellipsis is invalid"))))
|
||||
|
||||
(defun magit--ext-regexp-quote (string)
|
||||
"Like `reqexp-quote', but for Extended Regular Expressions."
|
||||
(let ((special (string-to-list "[*.\\?+^$({"))
|
||||
(quoted nil))
|
||||
(dolist (char string)
|
||||
(when (memq char special)
|
||||
(push ?\\ quoted))
|
||||
(push char quoted))
|
||||
(concat (nreverse quoted))))
|
||||
|
||||
;;; _
|
||||
(provide 'magit-base)
|
||||
;;; magit-base.el ends here
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-bisect.el --- Bisect support for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -63,10 +63,8 @@
|
||||
("-n" "Don't checkout commits" "--no-checkout")
|
||||
("-p" "Follow only first parent of a merge" "--first-parent"
|
||||
:if (lambda () (magit-git-version>= "2.29")))
|
||||
(6 magit-bisect:--term-old
|
||||
:if (lambda () (magit-git-version>= "2.7")))
|
||||
(6 magit-bisect:--term-new
|
||||
:if (lambda () (magit-git-version>= "2.7")))]
|
||||
(magit-bisect:--term-old :level 6)
|
||||
(magit-bisect:--term-new :level 6)]
|
||||
["Actions"
|
||||
("B" "Start" magit-bisect-start)
|
||||
("s" "Start script" magit-bisect-run)]]
|
||||
@@ -74,8 +72,7 @@
|
||||
:if magit-bisect-in-progress-p
|
||||
("B" "Bad" magit-bisect-bad)
|
||||
("g" "Good" magit-bisect-good)
|
||||
(6 "m" "Mark" magit-bisect-mark
|
||||
:if (lambda () (magit-git-version>= "2.7")))
|
||||
("m" "Mark" magit-bisect-mark :level 6)
|
||||
("k" "Skip" magit-bisect-skip)
|
||||
("r" "Reset" magit-bisect-reset)
|
||||
("s" "Run script" magit-bisect-run)])
|
||||
@@ -104,15 +101,7 @@ other actions from the bisect transient command (\
|
||||
(interactive (if (magit-bisect-in-progress-p)
|
||||
(user-error "Already bisecting")
|
||||
(magit-bisect-start-read-args)))
|
||||
(unless (magit-rev-ancestor-p good bad)
|
||||
(user-error
|
||||
"The %s revision (%s) has to be an ancestor of the %s one (%s)"
|
||||
(or (transient-arg-value "--term-old=" args) "good")
|
||||
good
|
||||
(or (transient-arg-value "--term-new=" args) "bad")
|
||||
bad))
|
||||
(when (magit-anything-modified-p)
|
||||
(user-error "Cannot bisect with uncommitted changes"))
|
||||
(magit-bisect-start--assert bad good args)
|
||||
(magit-repository-local-set 'bisect--first-parent
|
||||
(transient-arg-value "--first-parent" args))
|
||||
(magit-git-bisect "start" (list args bad good) t))
|
||||
@@ -130,6 +119,17 @@ other actions from the bisect transient command (\
|
||||
bad)
|
||||
args)))
|
||||
|
||||
(defun magit-bisect-start--assert (bad good args)
|
||||
(unless (magit-rev-ancestor-p good bad)
|
||||
(user-error
|
||||
"The %s revision (%s) has to be an ancestor of the %s one (%s)"
|
||||
(or (transient-arg-value "--term-old=" args) "good")
|
||||
good
|
||||
(or (transient-arg-value "--term-new=" args) "bad")
|
||||
bad))
|
||||
(when (magit-anything-modified-p)
|
||||
(user-error "Cannot bisect with uncommitted changes")))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-bisect-reset ()
|
||||
"After bisecting, cleanup bisection state and return to original `HEAD'."
|
||||
@@ -197,17 +197,17 @@ bisect run'."
|
||||
(magit-bisect-start-read-args))))
|
||||
(cons (read-shell-command "Bisect shell command: ") args)))
|
||||
(when (and bad good)
|
||||
(magit-bisect-start--assert bad good args)
|
||||
;; Avoid `magit-git-bisect' because it's asynchronous, but the
|
||||
;; next `git bisect run' call requires the bisect to be started.
|
||||
(magit-with-toplevel
|
||||
(magit-process-git
|
||||
(list :file (expand-file-name "BISECT_CMD_OUTPUT" (magit-gitdir)))
|
||||
(magit-process-git-arguments
|
||||
(list "bisect" "start" bad good args)))
|
||||
"bisect" "start" bad good args)
|
||||
(magit-refresh)))
|
||||
(magit--with-connection-local-variables
|
||||
(magit-git-bisect "run" (list shell-file-name
|
||||
shell-command-switch cmdline))))
|
||||
(with-connection-local-variables
|
||||
(magit-git-bisect "run" (list shell-file-name
|
||||
shell-command-switch cmdline))))
|
||||
|
||||
(defun magit-git-bisect (subcommand &optional args no-assert)
|
||||
(unless (or no-assert (magit-bisect-in-progress-p))
|
||||
@@ -256,7 +256,7 @@ bisect run'."
|
||||
(done-re "^\\([a-z0-9]\\{40,\\}\\) is the first bad commit$")
|
||||
(bad-line (or (and (string-match done-re (car lines))
|
||||
(pop lines))
|
||||
(--first (string-match done-re it) lines))))
|
||||
(seq-find (##string-match done-re %) lines))))
|
||||
(magit-insert-section ((eval (if bad-line 'commit 'bisect-output))
|
||||
(and bad-line (match-string 1 bad-line)))
|
||||
(magit-insert-heading
|
||||
@@ -270,7 +270,7 @@ bisect run'."
|
||||
"While bisecting, insert section visualizing the bisect state."
|
||||
(when (magit-bisect-in-progress-p)
|
||||
(magit-insert-section (bisect-view)
|
||||
(magit-insert-heading "Bisect Rest:")
|
||||
(magit-insert-heading t "Bisect Rest")
|
||||
(magit-git-wash (apply-partially #'magit-log-wash-log 'bisect-vis)
|
||||
"bisect" "visualize" "git" "log"
|
||||
"--format=%h%x00%D%x00%s" "--decorate=full"
|
||||
@@ -282,7 +282,7 @@ bisect run'."
|
||||
"While bisecting, insert section logging bisect progress."
|
||||
(when (magit-bisect-in-progress-p)
|
||||
(magit-insert-section (bisect-log)
|
||||
(magit-insert-heading "Bisect Log:")
|
||||
(magit-insert-heading t "Bisect Log")
|
||||
(magit-git-wash #'magit-wash-bisect-log "bisect" "log")
|
||||
(insert ?\n))))
|
||||
|
||||
@@ -299,9 +299,9 @@ bisect run'."
|
||||
(narrow-to-region beg (point))
|
||||
(goto-char (point-min))
|
||||
(magit-insert-section (bisect-item heading t)
|
||||
(insert (propertize heading 'font-lock-face
|
||||
'magit-section-secondary-heading))
|
||||
(magit-insert-heading)
|
||||
(magit-insert-heading
|
||||
(propertize heading 'font-lock-face
|
||||
'magit-section-secondary-heading))
|
||||
(magit-wash-sequence
|
||||
(apply-partially #'magit-log-wash-rev 'bisect-log
|
||||
(magit-abbrev-length)))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-blame.el --- Blame support for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -107,7 +107,7 @@ the background color.
|
||||
|
||||
Blame information is displayed using overlays. Such extensive
|
||||
use of overlays is known to slow down even basic operations, such
|
||||
as moving the cursor. To reduce the number of overlays the margin
|
||||
as moving the cursor. To reduce the number of overlays the margin
|
||||
style had to be removed from the default value of this option.
|
||||
|
||||
Note that the margin overlays are created even if another style
|
||||
@@ -157,25 +157,25 @@ and then turned on again when turning off the latter."
|
||||
:type '(choice (const :tag "No lighter" "") string))
|
||||
|
||||
(defcustom magit-blame-goto-chunk-hook
|
||||
'(magit-blame-maybe-update-revision-buffer
|
||||
magit-blame-maybe-show-message)
|
||||
(list #'magit-blame-maybe-update-revision-buffer
|
||||
#'magit-blame-maybe-show-message)
|
||||
"Hook run after point entered another chunk."
|
||||
:package-version '(magit . "2.13.0")
|
||||
:group 'magit-blame
|
||||
:type 'hook
|
||||
:get #'magit-hook-custom-get
|
||||
:options '(magit-blame-maybe-update-revision-buffer
|
||||
magit-blame-maybe-show-message))
|
||||
:options (list #'magit-blame-maybe-update-revision-buffer
|
||||
#'magit-blame-maybe-show-message))
|
||||
|
||||
;;; Faces
|
||||
|
||||
(defface magit-blame-highlight
|
||||
`((((class color) (background light))
|
||||
,@(and (>= emacs-major-version 27) '(:extend t))
|
||||
'((((class color) (background light))
|
||||
:extend t
|
||||
:background "grey80"
|
||||
:foreground "black")
|
||||
(((class color) (background dark))
|
||||
,@(and (>= emacs-major-version 27) '(:extend t))
|
||||
:extend t
|
||||
:background "grey25"
|
||||
:foreground "white"))
|
||||
"Face used for highlighting when blaming.
|
||||
@@ -199,7 +199,7 @@ Also see option `magit-blame-styles'."
|
||||
:group 'magit-faces)
|
||||
|
||||
(defface magit-blame-heading
|
||||
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
|
||||
'((t :extend t
|
||||
:inherit magit-blame-highlight
|
||||
:weight normal
|
||||
:slant normal))
|
||||
@@ -274,18 +274,18 @@ Also see option `magit-blame-styles'."
|
||||
(error "Cannot get blame chunk at eob"))
|
||||
(car (magit-blame--parse-chunk type))))))
|
||||
(noerror nil)
|
||||
(t (error "Buffer does not visit a tracked file")))))))
|
||||
((error "Buffer does not visit a tracked file")))))))
|
||||
|
||||
(defun magit-blame-chunk-at (pos)
|
||||
(--some (overlay-get it 'magit-blame-chunk)
|
||||
(overlays-at pos)))
|
||||
(seq-some (##overlay-get % 'magit-blame-chunk)
|
||||
(overlays-at pos)))
|
||||
|
||||
(defun magit-blame--overlay-at (&optional pos key)
|
||||
(unless pos
|
||||
(setq pos (point)))
|
||||
(--first (overlay-get it (or key 'magit-blame-chunk))
|
||||
(nconc (overlays-at pos)
|
||||
(overlays-in pos pos))))
|
||||
(seq-find (##overlay-get % (or key 'magit-blame-chunk))
|
||||
(nconc (overlays-at pos)
|
||||
(overlays-in pos pos))))
|
||||
|
||||
;;; Keymaps
|
||||
|
||||
@@ -346,7 +346,7 @@ in `magit-blame-read-only-mode-map' instead."
|
||||
(and (cl-find-if (lambda (style)
|
||||
(assq 'margin-format (cdr style)))
|
||||
magit-blame-styles)))
|
||||
(magit-blame--update-margin))
|
||||
(magit-blame--update-margin 'enable))
|
||||
(t
|
||||
(when (process-live-p magit-blame-process)
|
||||
(kill-process magit-blame-process)
|
||||
@@ -365,7 +365,7 @@ in `magit-blame-read-only-mode-map' instead."
|
||||
(kill-local-variable 'magit-blame-disabled-modes)
|
||||
(kill-local-variable 'magit-blame-type)
|
||||
(kill-local-variable 'magit-blame--style)
|
||||
(magit-blame--update-margin)
|
||||
(magit-blame--update-margin 'disable)
|
||||
(magit-blame--remove-overlays))))
|
||||
|
||||
(defun magit-blame--refresh ()
|
||||
@@ -453,6 +453,7 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
(let ((status (process-status process)))
|
||||
(when (memq status '(exit signal))
|
||||
(kill-buffer (process-buffer process))
|
||||
(kill-buffer (process-get process 'stderr-buf))
|
||||
(if (and (eq status 'exit)
|
||||
(zerop (process-exit-status process)))
|
||||
(unless quiet
|
||||
@@ -536,6 +537,8 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
|
||||
;;; Display
|
||||
|
||||
(defvar-local magit-blame--previous-margin-width nil)
|
||||
|
||||
(defsubst magit-blame--style-get (key)
|
||||
(cdr (assoc key (cdr magit-blame--style))))
|
||||
|
||||
@@ -596,15 +599,20 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
(magit-blame--update-heading-overlay ov)))
|
||||
|
||||
(defun magit-blame--make-highlight-overlay (chunk beg)
|
||||
(let ((ov (make-overlay beg (save-excursion
|
||||
(goto-char beg)
|
||||
(1+ (line-end-position))))))
|
||||
(let ((ov (make-overlay beg (1+ (magit--eol-position beg)))))
|
||||
(overlay-put ov 'magit-blame-chunk chunk)
|
||||
(overlay-put ov 'magit-blame-highlight t)
|
||||
(magit-blame--update-highlight-overlay ov)))
|
||||
|
||||
(defun magit-blame--update-margin ()
|
||||
(setq left-margin-width (or (magit-blame--style-get 'margin-width) 0))
|
||||
(defun magit-blame--update-margin (&optional action)
|
||||
(when (eq action 'enable)
|
||||
(setq magit-blame--previous-margin-width left-margin-width))
|
||||
(setq left-margin-width
|
||||
(if (eq action 'disable)
|
||||
(prog1 magit-blame--previous-margin-width
|
||||
(setq magit-blame--previous-margin-width nil))
|
||||
(or (magit-blame--style-get 'margin-width)
|
||||
magit-blame--previous-margin-width)))
|
||||
(set-window-buffer (selected-window) (current-buffer)))
|
||||
|
||||
(defun magit-blame--update-overlays ()
|
||||
@@ -643,7 +651,10 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
(overlay-put
|
||||
ov 'before-string
|
||||
(if-let ((format (magit-blame--style-get 'heading-format)))
|
||||
(magit-blame--format-string ov format 'magit-blame-heading)
|
||||
;; Use `default' as the last face to avoid picking up any face
|
||||
;; attributes from the first character of the text on which we
|
||||
;; put the overlay. See #5233.
|
||||
(magit-blame--format-string ov format '(magit-blame-heading default))
|
||||
(and (magit-blame--style-get 'show-lines)
|
||||
(or (not (magit-blame--style-get 'margin-format))
|
||||
(save-excursion
|
||||
@@ -651,7 +662,7 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
;; Special case of the special case described in
|
||||
;; `magit-blame--make-margin-overlay'. For empty
|
||||
;; lines it is not possible to show both overlays
|
||||
;; without the line being to high.
|
||||
;; without the line being too high.
|
||||
(not (= (point) (line-end-position)))))
|
||||
magit-blame-separator))))
|
||||
|
||||
@@ -682,11 +693,7 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
(propertize format 'font-lock-face face)
|
||||
(cl-flet* ((p0 (s f)
|
||||
(propertize s 'font-lock-face
|
||||
(if face
|
||||
(if (listp face)
|
||||
face
|
||||
(list f face))
|
||||
f)))
|
||||
(if face (cons f (ensure-list face)) f)))
|
||||
(p1 (k f)
|
||||
(p0 (cdr (assoc k revinfo)) f))
|
||||
(p2 (k1 k2 f)
|
||||
@@ -709,13 +716,12 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
str)))
|
||||
|
||||
(defun magit-blame--format-separator ()
|
||||
(propertize
|
||||
(concat (propertize "\s" 'display '(space :height (2)))
|
||||
(propertize "\n" 'line-height t))
|
||||
'font-lock-face `(:background
|
||||
,(face-attribute 'magit-blame-heading
|
||||
:background nil t)
|
||||
,@(and (>= emacs-major-version 27) '(:extend t)))))
|
||||
(propertize (concat (propertize "\s" 'display '(space :height (2)))
|
||||
(propertize "\n" 'line-height t))
|
||||
'font-lock-face
|
||||
`( :extend t
|
||||
:background
|
||||
,(face-attribute 'magit-blame-heading :background nil t))))
|
||||
|
||||
(defun magit-blame--format-time-string (time tz)
|
||||
(let* ((time-format (or (magit-blame--style-get 'time-format)
|
||||
@@ -736,14 +742,13 @@ modes is toggled, then this mode also gets toggled automatically.
|
||||
|
||||
(defun magit-blame-maybe-show-message ()
|
||||
(when (magit-blame--style-get 'show-message)
|
||||
(let ((message-log-max 0))
|
||||
(if-let ((msg (cdr (assoc "summary"
|
||||
(gethash (oref (magit-current-blame-chunk)
|
||||
orig-rev)
|
||||
magit-blame-cache)))))
|
||||
(progn (set-text-properties 0 (length msg) nil msg)
|
||||
(message msg))
|
||||
(message "Commit data not available yet. Still blaming.")))))
|
||||
(if-let ((msg (cdr (assoc "summary"
|
||||
(gethash (oref (magit-current-blame-chunk)
|
||||
orig-rev)
|
||||
magit-blame-cache)))))
|
||||
(progn (set-text-properties 0 (length msg) nil msg)
|
||||
(magit-msg "%S" msg))
|
||||
(magit-msg "Commit data not available yet. Still blaming."))))
|
||||
|
||||
;;; Commands
|
||||
|
||||
@@ -810,7 +815,7 @@ not turn on `read-only-mode'."
|
||||
(if-let ((chunk (magit-current-blame-chunk)))
|
||||
(unless (oref chunk prev-rev)
|
||||
(user-error "Chunk has no further history"))
|
||||
(user-error "Commit data not available yet. Still blaming."))
|
||||
(user-error "Still blaming, commit data not available yet"))
|
||||
(unless (magit-file-relative-name nil (not magit-buffer-file-name))
|
||||
(if buffer-file-name
|
||||
(user-error "Buffer isn't visiting a tracked file")
|
||||
@@ -878,7 +883,8 @@ then also kill the buffer."
|
||||
(user-error "No more chunks")))
|
||||
|
||||
(defun magit-blame-next-chunk-same-commit (&optional previous)
|
||||
"Move to the next chunk from the same commit.\n\n(fn)"
|
||||
"Move to the next chunk from the same commit.
|
||||
\n(fn)"
|
||||
(interactive)
|
||||
(if-let ((rev (oref (magit-current-blame-chunk) orig-rev)))
|
||||
(let ((pos (point)) ov)
|
||||
@@ -890,9 +896,9 @@ then also kill the buffer."
|
||||
#'previous-single-char-property-change
|
||||
#'next-single-char-property-change)
|
||||
pos 'magit-blame-chunk)))
|
||||
(when-let ((o (magit-blame--overlay-at pos)))
|
||||
(when (equal (oref (magit-blame-chunk-at pos) orig-rev) rev)
|
||||
(setq ov o)))))
|
||||
(when-let ((o (magit-blame--overlay-at pos))
|
||||
((equal (oref (magit-blame-chunk-at pos) orig-rev) rev)))
|
||||
(setq ov o))))
|
||||
(if ov
|
||||
(goto-char (overlay-start ov))
|
||||
(user-error "No more chunks from same commit")))
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
;;; magit-bookmark.el --- Bookmark support for Magit -*- lexical-binding:t -*-
|
||||
;;; magit-bookmark.el --- Bookmarks for Magit buffers -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Inspired by an earlier implementation by Yuri Khan.
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -30,6 +30,23 @@
|
||||
|
||||
(require 'magit)
|
||||
|
||||
(require 'bookmark)
|
||||
|
||||
;;; Common
|
||||
|
||||
(cl-defmethod magit-bookmark-get-filename (&context (major-mode magit-mode))
|
||||
(magit-toplevel))
|
||||
|
||||
(cl-defmethod magit-bookmark-get-buffer-create
|
||||
(bookmark (mode (derived-mode magit-mode)))
|
||||
(let ((default-directory (bookmark-get-filename bookmark))
|
||||
(magit-display-buffer-function #'identity)
|
||||
(magit-display-buffer-noselect t))
|
||||
(apply (intern (format "%s-setup-buffer"
|
||||
(substring (symbol-name mode) 0 -5)))
|
||||
(mapcar (##bookmark-prop-get bookmark %)
|
||||
(get mode 'magit-bookmark-variables)))))
|
||||
|
||||
;;; Diff
|
||||
;;;; Diff
|
||||
|
||||
@@ -48,7 +65,7 @@
|
||||
('undefined
|
||||
(delq nil (list magit-buffer-typearg magit-buffer-range-hashed))))
|
||||
(if magit-buffer-diff-files
|
||||
(concat " -- " (mapconcat #'identity magit-buffer-diff-files " "))
|
||||
(concat " -- " (string-join magit-buffer-diff-files " "))
|
||||
"")))
|
||||
|
||||
;;;; Revision
|
||||
@@ -62,7 +79,7 @@
|
||||
(format "magit-revision(%s %s)"
|
||||
(magit-rev-abbrev magit-buffer-revision)
|
||||
(if magit-buffer-diff-files
|
||||
(mapconcat #'identity magit-buffer-diff-files " ")
|
||||
(string-join magit-buffer-diff-files " ")
|
||||
(magit-rev-format "%s" magit-buffer-revision))))
|
||||
|
||||
;;;; Stash
|
||||
@@ -76,9 +93,15 @@
|
||||
(format "magit-stash(%s %s)"
|
||||
(magit-rev-abbrev magit-buffer-revision)
|
||||
(if magit-buffer-diff-files
|
||||
(mapconcat #'identity magit-buffer-diff-files " ")
|
||||
(string-join magit-buffer-diff-files " ")
|
||||
(magit-rev-format "%s" magit-buffer-revision))))
|
||||
|
||||
(cl-defmethod magit-bookmark--get-child-value
|
||||
(section &context (major-mode magit-stash-mode))
|
||||
(string-replace magit-buffer-revision
|
||||
magit-buffer-revision-hash
|
||||
(oref section value)))
|
||||
|
||||
;;; Log
|
||||
;;;; Log
|
||||
|
||||
@@ -89,9 +112,9 @@
|
||||
|
||||
(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode))
|
||||
(format "magit-log(%s%s)"
|
||||
(mapconcat #'identity magit-buffer-revisions " ")
|
||||
(string-join magit-buffer-revisions " ")
|
||||
(if magit-buffer-log-files
|
||||
(concat " -- " (mapconcat #'identity magit-buffer-log-files " "))
|
||||
(concat " -- " (string-join magit-buffer-log-files " "))
|
||||
"")))
|
||||
|
||||
;;;; Cherry
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-branch.el --- Branch support -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
(defcustom magit-branch-read-upstream-first t
|
||||
"Whether to read upstream before name of new branch when creating a branch.
|
||||
|
||||
`nil' Read the branch name first.
|
||||
`t' Read the upstream first.
|
||||
nil Read the branch name first.
|
||||
t Read the upstream first.
|
||||
`fallback' Read the upstream first, but if it turns out that the chosen
|
||||
value is not a valid upstream (because it cannot be resolved
|
||||
as an existing revision), then treat it as the name of the
|
||||
@@ -177,7 +177,7 @@ When t, then rename the branch named OLD on the remote specified
|
||||
remote and unless NEW already exists on the remote.
|
||||
|
||||
When `forge-only' and the `forge' package is available, then
|
||||
behave like `t' if the remote points to a repository on a forge
|
||||
behave like t if the remote points to a repository on a forge
|
||||
(currently Github or Gitlab), otherwise like `local-only'."
|
||||
:package-version '(magit . "2.90.0")
|
||||
:group 'magit-commands
|
||||
@@ -208,18 +208,24 @@ 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"
|
||||
["Arguments"
|
||||
(7 "-r" "Recurse submodules when checking out an existing branch"
|
||||
"--recurse-submodules"
|
||||
:if (lambda () (magit-git-version>= "2.13")))]
|
||||
["Variables"
|
||||
:if (lambda ()
|
||||
(and magit-branch-direct-configure
|
||||
(oref transient--prefix scope)))
|
||||
[:if (lambda () (and magit-branch-direct-configure (transient-scope)))
|
||||
:description
|
||||
(lambda ()
|
||||
(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)
|
||||
("p" magit-branch.<branch>.pushRemote)]
|
||||
[:if-non-nil magit-branch-direct-configure
|
||||
:description "Configure repository defaults"
|
||||
("R" magit-pull.rebase)
|
||||
("P" magit-remote.pushDefault)
|
||||
("B" "Update default branch" magit-update-default-branch
|
||||
:inapt-if-not magit-get-some-remote)]
|
||||
["Arguments"
|
||||
(7 "-r" "Recurse submodules when checking out an existing branch"
|
||||
"--recurse-submodules")]
|
||||
[["Checkout"
|
||||
("b" "branch/revision" magit-checkout)
|
||||
("l" "local branch" magit-branch-checkout)
|
||||
@@ -349,10 +355,10 @@ when using `magit-branch-and-checkout'."
|
||||
(interactive
|
||||
(let* ((current (magit-get-current-branch))
|
||||
(local (magit-list-local-branch-names))
|
||||
(remote (--filter (and (string-match "[^/]+/" it)
|
||||
(not (member (substring it (match-end 0))
|
||||
(cons "HEAD" local))))
|
||||
(magit-list-remote-branch-names)))
|
||||
(remote (seq-filter (##and (string-match "[^/]+/" %)
|
||||
(not (member (substring % (match-end 0))
|
||||
(cons "HEAD" local))))
|
||||
(magit-list-remote-branch-names)))
|
||||
(choices (nconc (delete current local) remote))
|
||||
(atpoint (magit-branch-at-point))
|
||||
(choice (magit-completing-read
|
||||
@@ -418,22 +424,21 @@ when using `magit-branch-and-checkout'."
|
||||
(defun magit-branch-read-args (prompt &optional default-start)
|
||||
(if magit-branch-read-upstream-first
|
||||
(let ((choice (magit-read-starting-point prompt nil default-start)))
|
||||
(if (magit-rev-verify choice)
|
||||
(list (magit-read-string-ns
|
||||
(if magit-completing-read--silent-default
|
||||
(format "%s (starting at `%s')" prompt choice)
|
||||
"Name for new branch")
|
||||
(let ((def (mapconcat #'identity
|
||||
(cdr (split-string choice "/"))
|
||||
"/")))
|
||||
(and (member choice (magit-list-remote-branch-names))
|
||||
(not (member def (magit-list-local-branch-names)))
|
||||
def)))
|
||||
choice)
|
||||
(if (eq magit-branch-read-upstream-first 'fallback)
|
||||
(list choice
|
||||
(magit-read-starting-point prompt choice default-start))
|
||||
(user-error "Not a valid starting-point: %s" choice))))
|
||||
(cond
|
||||
((magit-rev-verify choice)
|
||||
(list (magit-read-string-ns
|
||||
(if magit-completing-read--silent-default
|
||||
(format "%s (starting at `%s')" prompt choice)
|
||||
"Name for new branch")
|
||||
(let ((def (string-join (cdr (split-string choice "/")) "/")))
|
||||
(and (member choice (magit-list-remote-branch-names))
|
||||
(not (member def (magit-list-local-branch-names)))
|
||||
def)))
|
||||
choice))
|
||||
((eq magit-branch-read-upstream-first 'fallback)
|
||||
(list choice
|
||||
(magit-read-starting-point prompt choice default-start)))
|
||||
((user-error "Not a valid starting-point: %s" choice))))
|
||||
(let ((branch (magit-read-string-ns (concat prompt " named"))))
|
||||
(if (magit-branch-p branch)
|
||||
(magit-branch-read-args
|
||||
@@ -540,15 +545,12 @@ When resetting to another branch and a prefix argument is used,
|
||||
then also set the target branch as the upstream of the branch
|
||||
that is being reset."
|
||||
(interactive
|
||||
(let* ((atpoint (magit-local-branch-at-point))
|
||||
(branch (magit-read-local-branch "Reset branch" atpoint))
|
||||
(minibuffer-default-add-function (magit--minibuf-default-add-commit)))
|
||||
(let ((branch (magit-read-local-branch "Reset branch"
|
||||
(magit-local-branch-at-point))))
|
||||
(list branch
|
||||
(magit-completing-read (format "Reset %s to" branch)
|
||||
(delete branch (magit-list-branch-names))
|
||||
nil nil nil 'magit-revision-history
|
||||
(or (and (not (equal branch atpoint)) atpoint)
|
||||
(magit-get-upstream-branch branch)))
|
||||
(magit-read-branch-or-commit (format "Reset %s to" branch)
|
||||
(magit-get-upstream-branch branch)
|
||||
branch)
|
||||
current-prefix-arg)))
|
||||
(let ((magit-inhibit-refresh t))
|
||||
(if (equal branch (magit-get-current-branch))
|
||||
@@ -594,22 +596,23 @@ prompt is confusing."
|
||||
(setq branches
|
||||
(list (magit-read-branch-prefer-other
|
||||
(if force "Force delete branch" "Delete branch")))))
|
||||
(unless force
|
||||
(when-let ((unmerged (seq-remove #'magit-branch-merged-p branches)))
|
||||
(if (magit-confirm 'delete-unmerged-branch
|
||||
"Delete unmerged branch %s"
|
||||
"Delete %d unmerged branches"
|
||||
'noabort unmerged)
|
||||
(setq force branches)
|
||||
(or (setq branches
|
||||
(cl-set-difference branches unmerged :test #'equal))
|
||||
(user-error "Abort")))))
|
||||
(when-let (((not force))
|
||||
(unmerged (seq-remove #'magit-branch-merged-p branches)))
|
||||
(if (magit-confirm 'delete-unmerged-branch
|
||||
"Delete unmerged branch %s"
|
||||
"Delete %d unmerged branches"
|
||||
'noabort unmerged)
|
||||
(setq force branches)
|
||||
(or (setq branches
|
||||
(cl-set-difference branches unmerged :test #'equal))
|
||||
(user-error "Abort"))))
|
||||
(list branches force)))
|
||||
(let* ((refs (mapcar #'magit-ref-fullname branches))
|
||||
(ambiguous (--remove it refs)))
|
||||
(when ambiguous
|
||||
(let ((refs (mapcar #'magit-ref-fullname branches)))
|
||||
;; If a member of refs is nil, that means that
|
||||
;; the respective branch name is ambiguous.
|
||||
(when-let ((ambiguous (seq-filter #'null refs)))
|
||||
(user-error
|
||||
"%s ambiguous. Please cleanup using git directly."
|
||||
"%s ambiguous; please cleanup using git directly"
|
||||
(let ((len (length ambiguous)))
|
||||
(cond
|
||||
((= len 1)
|
||||
@@ -624,12 +627,12 @@ prompt is confusing."
|
||||
(offset (1+ (length remote))))
|
||||
(cond
|
||||
((magit-confirm 'delete-branch-on-remote
|
||||
(format "Deleting local %s. Also delete on %s"
|
||||
(magit-ref-fullname (car branches))
|
||||
remote)
|
||||
(format "Deleting %d local refs. Also delete on %s"
|
||||
(length refs)
|
||||
remote)
|
||||
(list "Deleting local %s. Also delete on %s"
|
||||
(magit-ref-fullname (car branches))
|
||||
remote)
|
||||
(list "Deleting %d local refs. Also delete on %s"
|
||||
(length refs)
|
||||
remote)
|
||||
'noabort refs)
|
||||
;; The ref may actually point at another rev on the remote,
|
||||
;; but this is better than nothing.
|
||||
@@ -641,7 +644,7 @@ prompt is confusing."
|
||||
"push"
|
||||
(and (or force magit-branch-delete-never-verify) "--no-verify")
|
||||
remote
|
||||
(--map (concat ":" (substring it offset)) branches))
|
||||
(mapcar (##concat ":" (substring % offset)) branches))
|
||||
;; If that is not the case, then this deletes the tracking branches.
|
||||
(set-process-sentinel
|
||||
magit-this-process
|
||||
@@ -715,8 +718,8 @@ prompt is confusing."
|
||||
(when (member refspec refspecs)
|
||||
(if (and (length= refspecs 1)
|
||||
(magit-confirm 'delete-pr-remote
|
||||
(format "Also delete remote %s (%s)" remote
|
||||
"no pull-request branch remains")
|
||||
(list "Also delete remote %s (%s)" remote
|
||||
"no pull-request branch remains")
|
||||
nil t))
|
||||
(magit-call-git "remote" "rm" remote)
|
||||
(magit-call-git "config" "--unset-all" variable
|
||||
@@ -728,11 +731,11 @@ prompt is confusing."
|
||||
(defun magit-delete-remote-branch-sentinel (remote refs process event)
|
||||
(when (memq (process-status process) '(exit signal))
|
||||
(if (= (process-exit-status process) 1)
|
||||
(if-let ((on-remote (--map (concat "refs/remotes/" remote "/" it)
|
||||
(magit-remote-list-branches remote)))
|
||||
(rest (--filter (and (not (member it on-remote))
|
||||
(magit-ref-exists-p it))
|
||||
refs)))
|
||||
(if-let ((on-remote (mapcar (##concat "refs/remotes/" remote "/" %)
|
||||
(magit-remote-list-branches remote)))
|
||||
(rest (seq-filter (##and (not (member % on-remote))
|
||||
(magit-ref-exists-p %))
|
||||
refs)))
|
||||
(progn
|
||||
(process-put process 'inhibit-refresh t)
|
||||
(magit-process-sentinel process event)
|
||||
@@ -784,14 +787,16 @@ the remote."
|
||||
(not (eq magit-branch-rename-push-target 'local-only))
|
||||
(or (not (eq magit-branch-rename-push-target 'forge-only))
|
||||
(and (require (quote forge) nil t)
|
||||
(fboundp 'forge--forge-remote-p)
|
||||
(forge--forge-remote-p remote))))
|
||||
(fboundp 'forge--split-forge-url)
|
||||
(and-let* ((url (magit-git-string
|
||||
"remote" "get-url" remote)))
|
||||
(forge--split-forge-url url)))))
|
||||
(let ((old-target (magit-get-push-branch old t))
|
||||
(new-target (magit-get-push-branch new t))
|
||||
(remote (magit-get-push-remote new)))
|
||||
(when (and old-target
|
||||
(not new-target)
|
||||
(magit-y-or-n-p (format "Also rename %S to %S on \"%s\""
|
||||
(magit-y-or-n-p (format "Also rename %S to %S on \"%s\"?"
|
||||
old new remote)))
|
||||
;; Rename on (i.e., within) the remote, but only if the
|
||||
;; destination ref doesn't exist yet. If that ref already
|
||||
@@ -820,14 +825,14 @@ and also rename the respective reflog file."
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-branch-unshelve (branch)
|
||||
"Unshelve a BRANCH
|
||||
"Unshelve a BRANCH.
|
||||
Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\",
|
||||
and also rename the respective reflog file."
|
||||
(interactive
|
||||
(list (magit-completing-read
|
||||
"Unshelve branch"
|
||||
(--map (substring it 8)
|
||||
(magit-list-refnames "refs/shelved"))
|
||||
(mapcar (##substring % 8)
|
||||
(magit-list-refnames "refs/shelved"))
|
||||
nil t)))
|
||||
(let ((old (concat "refs/shelved/" branch))
|
||||
(new (concat "refs/heads/" branch)))
|
||||
@@ -851,17 +856,16 @@ and also rename the respective reflog file."
|
||||
:man-page "git-branch"
|
||||
[:description
|
||||
(lambda ()
|
||||
(concat
|
||||
(propertize "Configure " 'face 'transient-heading)
|
||||
(propertize (oref transient--prefix scope) 'face 'magit-branch-local)))
|
||||
("d" magit-branch.<branch>.description)
|
||||
("u" magit-branch.<branch>.merge/remote)
|
||||
("r" magit-branch.<branch>.rebase)
|
||||
("p" magit-branch.<branch>.pushRemote)]
|
||||
(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)
|
||||
("p" magit-branch.<branch>.pushRemote)]
|
||||
["Configure repository defaults"
|
||||
("R" magit-pull.rebase)
|
||||
("P" magit-remote.pushDefault)
|
||||
("b" "Update default branch" magit-update-default-branch
|
||||
("B" "Update default branch" magit-update-default-branch
|
||||
:inapt-if-not magit-get-some-remote)]
|
||||
["Configure branch creation"
|
||||
("a m" magit-branch.autoSetupMerge)
|
||||
@@ -896,7 +900,7 @@ and also rename the respective reflog file."
|
||||
:class 'magit--git-branch:upstream)
|
||||
|
||||
(cl-defmethod transient-init-value ((obj magit--git-branch:upstream))
|
||||
(when-let* ((branch (oref transient--prefix scope))
|
||||
(when-let* ((branch (transient-scope))
|
||||
(remote (magit-get "branch" branch "remote"))
|
||||
(merge (magit-get "branch" branch "merge")))
|
||||
(oset obj value (list remote merge))))
|
||||
@@ -904,19 +908,19 @@ and also rename the respective reflog file."
|
||||
(cl-defmethod transient-infix-read ((obj magit--git-branch:upstream))
|
||||
(if (oref obj value)
|
||||
(oset obj value nil)
|
||||
(magit-read-upstream-branch (oref transient--prefix scope) "Upstream")))
|
||||
(magit-read-upstream-branch (transient-scope) "Upstream")))
|
||||
|
||||
(cl-defmethod transient-infix-set ((obj magit--git-branch:upstream) refname)
|
||||
(magit-set-upstream-branch (oref transient--prefix scope) refname)
|
||||
(magit-set-upstream-branch (transient-scope) refname)
|
||||
(oset obj value
|
||||
(and-let* ((branch (oref transient--prefix scope))
|
||||
(and-let* ((branch (transient-scope))
|
||||
(r (magit-get "branch" branch "remote"))
|
||||
(m (magit-get "branch" branch "merge")))
|
||||
(list r m)))
|
||||
(magit-refresh))
|
||||
|
||||
(cl-defmethod transient-format ((obj magit--git-branch:upstream))
|
||||
(let ((branch (oref transient--prefix scope)))
|
||||
(let ((branch (transient-scope)))
|
||||
(format-spec
|
||||
(oref obj format)
|
||||
`((?k . ,(transient-format-key obj))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-bundle.el --- Bundle support for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with Magit. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This library implements support for "git bundle".
|
||||
;; The entry point is the `magit-bundle' menu command.
|
||||
|
||||
;; See (man "git-bundle").
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'magit)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-clone.el --- Clone a repository -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -135,9 +135,7 @@ directory where the repository has been cloned."
|
||||
["Setup arguments"
|
||||
("-o" "Set name of remote" ("-o" "--origin="))
|
||||
("-b" "Set HEAD branch" ("-b" "--branch="))
|
||||
(magit-clone:--filter
|
||||
:if (lambda () (magit-git-version>= "2.17.0"))
|
||||
:level 7)
|
||||
(magit-clone:--filter :level 7)
|
||||
("-g" "Separate git directory" "--separate-git-dir="
|
||||
transient-read-directory :level 7)
|
||||
("-t" "Use template directory" "--template="
|
||||
@@ -150,9 +148,7 @@ directory where the repository has been cloned."
|
||||
("s" "shallow" magit-clone-shallow)
|
||||
("d" "shallow since date" magit-clone-shallow-since :level 7)
|
||||
("e" "shallow excluding" magit-clone-shallow-exclude :level 7)
|
||||
(">" "sparse checkout" magit-clone-sparse
|
||||
:if (lambda () (magit-git-version>= "2.25.0"))
|
||||
:level 6)
|
||||
(">" "sparse checkout" magit-clone-sparse :level 6)
|
||||
("b" "bare" magit-clone-bare)
|
||||
("m" "mirror" magit-clone-mirror)]
|
||||
(interactive (list (or magit-clone-always-transient current-prefix-arg)))
|
||||
@@ -278,9 +274,6 @@ Then show the status buffer for the new repository."
|
||||
(unless magit-clone-set-remote-head
|
||||
(magit-remote-unset-head remote))))
|
||||
(when (and sparse checkout)
|
||||
(when (magit-git-version< "2.25.0")
|
||||
(user-error
|
||||
"`git sparse-checkout' not available until Git v2.25"))
|
||||
(let ((default-directory directory))
|
||||
(magit-call-git "sparse-checkout" "init" "--cone")
|
||||
(magit-call-git "checkout" (magit-get-current-branch))))
|
||||
@@ -315,7 +308,7 @@ Then show the status buffer for the new repository."
|
||||
(concat "file://"
|
||||
(magit-convert-filename-for-git
|
||||
(read-directory-name "Clone repository: file://"))))
|
||||
(?b "or [b]undle"
|
||||
(?b "[b]undle"
|
||||
(magit-convert-filename-for-git
|
||||
(read-file-name "Clone from bundle: ")))))
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-commit.el --- Create Git commits -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -127,26 +127,31 @@ Also see https://github.com/magit/magit/issues/4132."
|
||||
("-n" "Disable hooks" ("-n" "--no-verify"))
|
||||
("-R" "Claim authorship and reset author date" "--reset-author")
|
||||
(magit:--author :description "Override the author")
|
||||
(7 "-D" "Override the author date" "--date=" transient-read-date)
|
||||
("-s" "Add Signed-off-by line" ("-s" "--signoff"))
|
||||
(5 magit:--gpg-sign)
|
||||
(magit-commit:--date :level 7)
|
||||
(magit:--gpg-sign :level 5)
|
||||
(magit:--signoff)
|
||||
(magit-commit:--reuse-message)]
|
||||
[["Create"
|
||||
("c" "Commit" magit-commit-create)]
|
||||
["Edit HEAD"
|
||||
("e" "Extend" magit-commit-extend)
|
||||
("w" "Reword" magit-commit-reword)
|
||||
""
|
||||
("a" "Amend" magit-commit-amend)
|
||||
(6 "n" "Reshelve" magit-commit-reshelve)]
|
||||
""
|
||||
("w" "Reword" magit-commit-reword)
|
||||
("d" "Reshelve" magit-commit-reshelve :level 0)]
|
||||
["Edit"
|
||||
("f" "Fixup" magit-commit-fixup)
|
||||
("s" "Squash" magit-commit-squash)
|
||||
("A" "Augment" magit-commit-augment)
|
||||
(6 "x" "Absorb changes" magit-commit-autofixup)
|
||||
(6 "X" "Absorb modules" magit-commit-absorb-modules)]
|
||||
[""
|
||||
("A" "Alter" magit-commit-alter)
|
||||
("n" "Augment" magit-commit-augment)
|
||||
("W" "Revise" magit-commit-revise)]
|
||||
["Edit and rebase"
|
||||
("F" "Instant fixup" magit-commit-instant-fixup)
|
||||
("S" "Instant squash" magit-commit-instant-squash)]]
|
||||
("S" "Instant squash" magit-commit-instant-squash)]
|
||||
["Spread across commits"
|
||||
("x" "Modified files" magit-commit-autofixup :level 6)
|
||||
("X" "Updated modules" magit-commit-absorb-modules :level 6)]]
|
||||
(interactive)
|
||||
(if-let ((buffer (magit-commit-message-buffer)))
|
||||
(switch-to-buffer buffer)
|
||||
@@ -155,6 +160,13 @@ Also see https://github.com/magit/magit/issues/4132."
|
||||
(defun magit-commit-arguments nil
|
||||
(transient-args 'magit-commit))
|
||||
|
||||
(transient-define-argument magit-commit:--date ()
|
||||
:description "Override the author date"
|
||||
:class 'transient-option
|
||||
:shortarg "-D"
|
||||
:argument "--date="
|
||||
:reader #'transient-read-date)
|
||||
|
||||
(transient-define-argument magit-commit:--reuse-message ()
|
||||
:description "Reuse commit message"
|
||||
:class 'transient-option
|
||||
@@ -171,15 +183,12 @@ Also see https://github.com/magit/magit/issues/4132."
|
||||
"ORIG_HEAD"))))
|
||||
|
||||
;;; Commands
|
||||
;;;; Create
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-create (&optional args)
|
||||
"Create a new commit on `HEAD'.
|
||||
With a prefix argument, amend to the commit at `HEAD' instead.
|
||||
\n(git commit [--amend] ARGS)"
|
||||
(interactive (if current-prefix-arg
|
||||
(list (cons "--amend" (magit-commit-arguments)))
|
||||
(list (magit-commit-arguments))))
|
||||
"Create a new commit."
|
||||
(interactive (list (magit-commit-arguments)))
|
||||
(cond ((member "--all" args)
|
||||
(setq this-command 'magit-commit--all))
|
||||
((member "--allow-empty" args)
|
||||
@@ -188,22 +197,17 @@ With a prefix argument, amend to the commit at `HEAD' instead.
|
||||
(let ((default-directory (magit-toplevel)))
|
||||
(magit-run-git-with-editor "commit" args))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-amend (&optional args)
|
||||
"Amend the last commit.
|
||||
\n(git commit --amend ARGS)"
|
||||
(interactive (list (magit-commit-arguments)))
|
||||
(magit-commit-amend-assert)
|
||||
(magit-run-git-with-editor "commit" "--amend" args))
|
||||
;;;; Edit HEAD
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-extend (&optional args override-date)
|
||||
"Amend the last commit, without editing the message.
|
||||
"Amend staged changes to the last commit, without editing its message.
|
||||
|
||||
With a prefix argument keep the committer date, otherwise change
|
||||
it. The option `magit-commit-extend-override-date' can be used
|
||||
to inverse the meaning of the prefix argument. \n(git commit
|
||||
--amend --no-edit)"
|
||||
With a prefix argument do not update the committer date; without an
|
||||
argument update it. The option `magit-commit-extend-override-date'
|
||||
can be used to inverse the meaning of the prefix argument. Called
|
||||
non-interactively, the optional OVERRIDE-DATE argument controls this
|
||||
behavior, and the option is of no relevance."
|
||||
(interactive (list (magit-commit-arguments)
|
||||
(if current-prefix-arg
|
||||
(not magit-commit-extend-override-date)
|
||||
@@ -216,17 +220,22 @@ to inverse the meaning of the prefix argument. \n(git commit
|
||||
(("GIT_COMMITTER_DATE" (magit-rev-format "%cD")))
|
||||
(magit-run-git-with-editor "commit" "--amend" "--no-edit" args)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-amend (&optional args)
|
||||
"Amend staged changes (if any) to the last commit, and edit its message."
|
||||
(interactive (list (magit-commit-arguments)))
|
||||
(magit-commit-amend-assert)
|
||||
(magit-run-git-with-editor "commit" "--amend" args))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-reword (&optional args override-date)
|
||||
"Reword the last commit, ignoring staged changes.
|
||||
"Reword the message of the last commit, without amending its tree.
|
||||
|
||||
With a prefix argument keep the committer date, otherwise change
|
||||
it. The option `magit-commit-reword-override-date' can be used
|
||||
to inverse the meaning of the prefix argument.
|
||||
|
||||
Non-interactively respect the optional OVERRIDE-DATE argument
|
||||
and ignore the option.
|
||||
\n(git commit --amend --only)"
|
||||
With a prefix argument do not update the committer date; without an
|
||||
argument update it. The option `magit-commit-reword-override-date'
|
||||
can be used to inverse the meaning of the prefix argument. Called
|
||||
non-interactively, the optional OVERRIDE-DATE argument controls this
|
||||
behavior, and the option is of no relevance."
|
||||
(interactive (list (magit-commit-arguments)
|
||||
(if current-prefix-arg
|
||||
(not magit-commit-reword-override-date)
|
||||
@@ -239,66 +248,139 @@ and ignore the option.
|
||||
(("GIT_COMMITTER_DATE" (magit-rev-format "%cD")))
|
||||
(magit-run-git-with-editor "commit" "--amend" "--only" args))))
|
||||
|
||||
;;;; Edit
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-fixup (&optional commit args)
|
||||
"Create a fixup commit.
|
||||
"Create a fixup commit, leaving the original commit message untouched.
|
||||
|
||||
With a prefix argument the target COMMIT has to be confirmed.
|
||||
Otherwise the commit at point may be used without confirmation
|
||||
depending on the value of option `magit-commit-squash-confirm'."
|
||||
If there is a reachable commit at point, target that. Otherwise prompt
|
||||
for a commit. If `magit-commit-squash-confirm' is non-nil, always make
|
||||
the user explicitly select a commit, in a buffer dedicated to that task.
|
||||
|
||||
During a later rebase, when this commit gets squashed into its targeted
|
||||
commit, the original message of the targeted commit is used as-is.
|
||||
|
||||
In other words, call \"git commit --fixup=COMMIT --no-edit\"."
|
||||
(interactive (list (magit-commit-at-point)
|
||||
(magit-commit-arguments)))
|
||||
(magit-commit-squash-internal "--fixup" commit args))
|
||||
(magit-commit-squash-internal "--fixup=" commit args))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-squash (&optional commit args)
|
||||
"Create a squash commit, without editing the squash message.
|
||||
"Create a squash commit, without the user authoring a commit message.
|
||||
|
||||
With a prefix argument the target COMMIT has to be confirmed.
|
||||
Otherwise the commit at point may be used without confirmation
|
||||
depending on the value of option `magit-commit-squash-confirm'.
|
||||
If there is a reachable commit at point, target that. Otherwise prompt
|
||||
for a commit. If `magit-commit-squash-confirm' is non-nil, always make
|
||||
the user explicitly select a commit, in a buffer dedicated to that task.
|
||||
|
||||
If you want to immediately add a message to the squash commit,
|
||||
then use `magit-commit-augment' instead of this command."
|
||||
During a later rebase, when this commit gets squashed into its targeted
|
||||
commit, the user is given a chance to edit the original message to take
|
||||
the changes from the squash commit into account.
|
||||
|
||||
In other words, call \"git commit --squash=COMMIT --no-edit\"."
|
||||
(interactive (list (magit-commit-at-point)
|
||||
(magit-commit-arguments)))
|
||||
(magit-commit-squash-internal "--squash" commit args))
|
||||
(magit-commit-squash-internal "--squash=" commit args))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-alter (&optional commit args)
|
||||
"Create a squash commit, authoring the final commit message now.
|
||||
|
||||
If there is a reachable commit at point, target that. Otherwise prompt
|
||||
for a commit. If `magit-commit-squash-confirm' is non-nil, always make
|
||||
the user explicitly select a commit, in a buffer dedicated to that task.
|
||||
|
||||
During a later rebase, when this commit gets squashed into its targeted
|
||||
commit, the original message of the targeted commit is replaced with the
|
||||
message of this commit, without the user automatically being given a
|
||||
chance to edit again.
|
||||
|
||||
In other words, call \"git commit --fixup=amend:COMMIT --edit\"."
|
||||
(interactive (list (magit-commit-at-point)
|
||||
(magit-commit-arguments)))
|
||||
(magit-commit-squash-internal "--fixup=amend:" commit args nil 'edit))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-augment (&optional commit args)
|
||||
"Create a squash commit, editing the squash message.
|
||||
"Create a squash commit, authoring a new temporary commit message.
|
||||
|
||||
With a prefix argument the target COMMIT has to be confirmed.
|
||||
Otherwise the commit at point may be used without confirmation
|
||||
depending on the value of option `magit-commit-squash-confirm'."
|
||||
If there is a reachable commit at point, target that. Otherwise prompt
|
||||
for a commit. If `magit-commit-squash-confirm' is non-nil, always make
|
||||
the user explicitly select a commit, in a buffer dedicated to that task.
|
||||
|
||||
During a later rebase, when this commit gets squashed into its targeted
|
||||
commit, the user is asked to write a final commit message, in a buffer
|
||||
that starts out containing both the original commit message, as well as
|
||||
the temporary commit message of the squash commit.
|
||||
|
||||
In other words, call \"git commit --squash=COMMIT --edit\"."
|
||||
(interactive (list (magit-commit-at-point)
|
||||
(magit-commit-arguments)))
|
||||
(magit-commit-squash-internal "--squash" commit args nil t))
|
||||
(magit-commit-squash-internal "--squash=" commit args nil 'edit))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-revise (&optional commit args)
|
||||
"Reword the message of an existing commit, without editing its tree.
|
||||
|
||||
If there is a reachable commit at point, target that. Otherwise prompt
|
||||
for a commit. If `magit-commit-squash-confirm' is non-nil, always make
|
||||
the user explicitly select a commit, in a buffer dedicated to that task.
|
||||
|
||||
During a later rebase, when this commit gets squashed into its targeted
|
||||
commit, a combined commit is created which uses the message of the fixup
|
||||
commit and the tree of the targeted commit.
|
||||
|
||||
In other words, call \"git commit --fixup=reword:COMMIT --edit\"."
|
||||
(interactive (list (magit-commit-at-point)
|
||||
(magit-commit-arguments)))
|
||||
(magit-commit-squash-internal "--fixup=reword:" commit args 'nopatch 'edit))
|
||||
|
||||
;;;; Edit and Rebase
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-instant-fixup (&optional commit args)
|
||||
"Create a fixup commit targeting COMMIT and instantly rebase."
|
||||
"Create a fixup commit, and immediately combine it with its target.
|
||||
|
||||
If there is a reachable commit at point, target that. Otherwise prompt
|
||||
for a commit. If `magit-commit-squash-confirm' is non-nil, always make
|
||||
the user explicitly select a commit, in a buffer dedicated to that task.
|
||||
|
||||
Leave the original commit message of the targeted commit untouched.
|
||||
|
||||
Like `magit-commit-fixup' but also run a `--autofixup' rebase."
|
||||
(interactive (list (magit-commit-at-point)
|
||||
(magit-commit-arguments)))
|
||||
(magit-commit-squash-internal "--fixup" commit args t))
|
||||
(magit-commit-squash-internal "--fixup=" commit args nil nil 'rebase))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-instant-squash (&optional commit args)
|
||||
"Create a squash commit targeting COMMIT and instantly rebase."
|
||||
"Create a squash commit, and immediately combine it with its target.
|
||||
|
||||
If there is a reachable commit at point, target that. Otherwise prompt
|
||||
for a commit. If `magit-commit-squash-confirm' is non-nil, always make
|
||||
the user explicitly select a commit, in a buffer dedicated to that task.
|
||||
|
||||
Turing the rebase phase, when the two commits are being squashed, ask
|
||||
the user to author the final commit message, based on the original
|
||||
message of the targeted commit.
|
||||
|
||||
Like `magit-commit-squash' but also run a `--autofixup' rebase."
|
||||
(interactive (list (magit-commit-at-point)
|
||||
(magit-commit-arguments)))
|
||||
(magit-commit-squash-internal "--squash" commit args t))
|
||||
(magit-commit-squash-internal "--squash=" commit args nil nil 'rebase))
|
||||
|
||||
;;;; Internal
|
||||
|
||||
(defun magit-commit-squash-internal
|
||||
(option commit &optional args rebase edit confirmed)
|
||||
(when-let ((args (magit-commit-assert args (not edit))))
|
||||
(when commit
|
||||
(when (and rebase (not (magit-rev-ancestor-p commit "HEAD")))
|
||||
(magit-read-char-case
|
||||
(format "%s isn't an ancestor of HEAD. " commit) nil
|
||||
(?c "[c]reate without rebasing" (setq rebase nil))
|
||||
(?s "[s]elect other" (setq commit nil))
|
||||
(?a "[a]bort" (user-error "Quit")))))
|
||||
(option commit &optional args nopatch edit rebase confirmed)
|
||||
(when-let ((args (magit-commit-assert args nopatch (not edit))))
|
||||
(when (and commit rebase (not (magit-rev-ancestor-p commit "HEAD")))
|
||||
(magit-read-char-case
|
||||
(format "%s isn't an ancestor of HEAD. " commit) nil
|
||||
(?c "[c]reate without rebasing" (setq rebase nil))
|
||||
(?s "[s]elect other" (setq commit nil))
|
||||
(?a "[a]bort" (user-error "Quit"))))
|
||||
(when commit
|
||||
(setq commit (magit-rebase-interactive-assert commit t)))
|
||||
(if (and commit
|
||||
@@ -307,9 +389,8 @@ depending on the value of option `magit-commit-squash-confirm'."
|
||||
current-prefix-arg
|
||||
magit-commit-squash-confirm))))
|
||||
(let ((magit-commit-show-diff nil))
|
||||
(push (concat option "=" commit) args)
|
||||
(unless edit
|
||||
(push "--no-edit" args))
|
||||
(push (concat option commit) args)
|
||||
(push (if edit "--edit" "--no-edit") args)
|
||||
(if rebase
|
||||
(magit-with-editor
|
||||
(magit-call-git
|
||||
@@ -323,7 +404,7 @@ depending on the value of option `magit-commit-squash-confirm'."
|
||||
(magit-log-select
|
||||
(lambda (commit)
|
||||
(when (and (magit-commit-squash-internal option commit args
|
||||
rebase edit t)
|
||||
nopatch edit rebase t)
|
||||
rebase)
|
||||
(magit-commit-amend-assert commit)
|
||||
(magit-rebase-interactive-1 commit
|
||||
@@ -334,7 +415,7 @@ depending on the value of option `magit-commit-squash-confirm'."
|
||||
(format "Type %%p on a commit to %s into it,"
|
||||
(substring option 2))
|
||||
nil nil nil commit))
|
||||
(when magit-commit-show-diff
|
||||
(when (and magit-commit-show-diff (not nopatch))
|
||||
(let ((magit-display-buffer-noselect t))
|
||||
(apply #'magit-diff-staged nil (magit-diff-arguments)))))))
|
||||
|
||||
@@ -347,8 +428,9 @@ depending on the value of option `magit-commit-squash-confirm'."
|
||||
(concat m1 "%d public branches" m2)
|
||||
nil branches))))
|
||||
|
||||
(defun magit-commit-assert (args &optional strict)
|
||||
(defun magit-commit-assert (args &optional nopatch strict)
|
||||
(cond
|
||||
(nopatch (or args (list "--")))
|
||||
((or (magit-anything-staged-p)
|
||||
(and (magit-anything-unstaged-p)
|
||||
;; ^ Everything of nothing is still nothing.
|
||||
@@ -380,7 +462,7 @@ depending on the value of option `magit-commit-squash-confirm'."
|
||||
(user-error "Nothing staged (or unstaged)"))
|
||||
(magit-commit-ask-to-stage
|
||||
(when (eq magit-commit-ask-to-stage 'verbose)
|
||||
(magit-diff-unstaged))
|
||||
(apply #'magit-diff-unstaged (magit-diff-arguments)))
|
||||
(prog1 (when (or (eq magit-commit-ask-to-stage 'stage)
|
||||
(y-or-n-p
|
||||
"Nothing staged. Commit all uncommitted changes? "))
|
||||
@@ -392,11 +474,13 @@ depending on the value of option `magit-commit-squash-confirm'."
|
||||
(t
|
||||
(user-error "Nothing staged"))))
|
||||
|
||||
;;;; Reshelve
|
||||
|
||||
(defvar magit--reshelve-history nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-reshelve (date update-author &optional args)
|
||||
"Change the committer date and possibly the author date of `HEAD'.
|
||||
"Change committer (and possibly author) date of the last commit.
|
||||
|
||||
The current time is used as the initial minibuffer input and the
|
||||
original author or committer date is available as the previous
|
||||
@@ -426,6 +510,8 @@ is updated:
|
||||
(and update-author (concat "--date=" date))
|
||||
args)))
|
||||
|
||||
;;;; Spread
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-commit-absorb-modules (phase commit)
|
||||
"Spread modified modules across recent commits."
|
||||
@@ -457,9 +543,10 @@ With a prefix argument use a transient command to select infix
|
||||
arguments. This command requires git-absorb executable, which
|
||||
is available from https://github.com/tummychow/git-absorb.
|
||||
See `magit-commit-autofixup' for an alternative implementation."
|
||||
:value '("-v")
|
||||
["Arguments"
|
||||
("-f" "Skip safety checks" ("-f" "--force"))
|
||||
("-v" "Display more output" ("-v" "--verbose"))]
|
||||
("-f" "Skip safety checks" ("-f" "--force"))
|
||||
("-v" "Increase verbosity" ("-v" "--verbose"))]
|
||||
["Actions"
|
||||
("x" "Absorb" magit-commit-absorb)]
|
||||
(interactive (if current-prefix-arg
|
||||
@@ -482,27 +569,31 @@ See `magit-commit-autofixup' for an alternative implementation."
|
||||
(when commit
|
||||
(setq commit (magit-rebase-interactive-assert commit t)))
|
||||
(if (and commit (eq phase 'run))
|
||||
(progn (magit-run-git-async "absorb" "-v" args "-b" commit) t)
|
||||
(progn (magit-run-git-async "absorb" args "-b" commit) t)
|
||||
(magit-log-select
|
||||
(lambda (commit)
|
||||
(with-no-warnings ; about non-interactive use
|
||||
(magit-commit-absorb 'run commit args)))
|
||||
nil nil nil nil commit))))
|
||||
|
||||
(transient-augment-suffix magit-commit-absorb :transient 'transient--do-exit)
|
||||
|
||||
;;;###autoload (autoload 'magit-commit-autofixup "magit-commit" nil t)
|
||||
(transient-define-prefix magit-commit-autofixup (phase commit args)
|
||||
"Spread staged or unstaged changes across recent commits.
|
||||
|
||||
If there are any staged then spread only those, otherwise
|
||||
spread all unstaged changes. With a prefix argument use a
|
||||
transient command to select infix arguments.
|
||||
If there are any staged then spread only those, otherwise spread all
|
||||
unstaged changes. With a prefix argument use a transient command to
|
||||
select infix arguments.
|
||||
|
||||
This command requires the git-autofixup script, which is
|
||||
available from https://github.com/torbiak/git-autofixup.
|
||||
See `magit-commit-absorb' for an alternative implementation."
|
||||
This command requires the git-autofixup script, which is available from
|
||||
https://github.com/torbiak/git-autofixup. See `magit-commit-absorb' for
|
||||
an alternative implementation."
|
||||
:value '("-vv")
|
||||
["Arguments"
|
||||
(magit-autofixup:--context)
|
||||
(magit-autofixup:--strict)]
|
||||
(magit-autofixup:--strict)
|
||||
("-v" "Increase verbosity" "-vv")]
|
||||
["Actions"
|
||||
("x" "Absorb" magit-commit-autofixup)]
|
||||
(interactive (if current-prefix-arg
|
||||
@@ -520,13 +611,15 @@ See `magit-commit-absorb' for an alternative implementation."
|
||||
(when commit
|
||||
(setq commit (magit-rebase-interactive-assert commit t)))
|
||||
(if (and commit (eq phase 'run))
|
||||
(progn (magit-run-git-async "autofixup" "-vv" args commit) t)
|
||||
(progn (magit-run-git-async "autofixup" args commit) t)
|
||||
(magit-log-select
|
||||
(lambda (commit)
|
||||
(with-no-warnings ; about non-interactive use
|
||||
(magit-commit-autofixup 'run commit args)))
|
||||
nil nil nil nil commit))))
|
||||
|
||||
(transient-augment-suffix magit-commit-autofixup :transient 'transient--do-exit)
|
||||
|
||||
(transient-define-argument magit-autofixup:--context ()
|
||||
:description "Diff context lines"
|
||||
:class 'transient-option
|
||||
@@ -541,12 +634,14 @@ See `magit-commit-absorb' for an alternative implementation."
|
||||
:argument "--strict="
|
||||
:reader #'transient-read-number-N0)
|
||||
|
||||
;;;; Hooks
|
||||
|
||||
(defvar magit-post-commit-hook-commands
|
||||
'(magit-commit-extend
|
||||
magit-commit-fixup
|
||||
magit-commit-augment
|
||||
magit-commit-instant-fixup
|
||||
magit-commit-instant-squash))
|
||||
(list #'magit-commit-extend
|
||||
#'magit-commit-fixup
|
||||
#'magit-commit-augment
|
||||
#'magit-commit-instant-fixup
|
||||
#'magit-commit-instant-squash))
|
||||
|
||||
(defun magit-run-post-commit-hook ()
|
||||
(when (and (not this-command)
|
||||
@@ -648,10 +743,10 @@ See `magit-commit-absorb' for an alternative implementation."
|
||||
(defun magit-commit-message-buffer ()
|
||||
(let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG
|
||||
(topdir (magit-toplevel)))
|
||||
(--first (equal topdir (with-current-buffer it
|
||||
(and git-commit-mode (magit-toplevel))))
|
||||
(append (buffer-list (selected-frame))
|
||||
(buffer-list)))))
|
||||
(seq-find (##equal topdir (with-current-buffer %
|
||||
(and git-commit-mode (magit-toplevel))))
|
||||
(append (buffer-list (selected-frame))
|
||||
(buffer-list)))))
|
||||
|
||||
(defvar magit-commit-add-log-insert-function #'magit-commit-add-log-insert
|
||||
"Used by `magit-commit-add-log' to insert a single entry.")
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-core.el --- Core functionality -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -37,15 +37,6 @@
|
||||
(require 'magit-transient)
|
||||
(require 'magit-autorevert)
|
||||
|
||||
(when (and (not magit-inhibit-libgit)
|
||||
(magit--libgit-available-p))
|
||||
(condition-case err
|
||||
(require 'magit-libgit)
|
||||
(error
|
||||
(setq magit-inhibit-libgit 'error)
|
||||
(message "Error while loading `magit-libgit': %S" err)
|
||||
(message "That is not fatal. The `libegit2' module just won't be used."))))
|
||||
|
||||
;;; Options
|
||||
|
||||
(defgroup magit nil
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
:group 'magit-extensions)
|
||||
|
||||
(defcustom magit-ediff-quit-hook
|
||||
'(magit-ediff-cleanup-auxiliary-buffers
|
||||
magit-ediff-restore-previous-winconf)
|
||||
(list #'magit-ediff-cleanup-auxiliary-buffers
|
||||
#'magit-ediff-restore-previous-winconf)
|
||||
"Hooks to run after finishing Ediff, when that was invoked using Magit.
|
||||
The hooks are run in the Ediff control buffer. This is similar
|
||||
to `ediff-quit-hook' but takes the needs of Magit into account.
|
||||
@@ -53,8 +53,8 @@ invoked using Magit."
|
||||
:group 'magit-ediff
|
||||
:type 'hook
|
||||
:get #'magit-hook-custom-get
|
||||
:options '(magit-ediff-cleanup-auxiliary-buffers
|
||||
magit-ediff-restore-previous-winconf))
|
||||
:options (list #'magit-ediff-cleanup-auxiliary-buffers
|
||||
#'magit-ediff-restore-previous-winconf))
|
||||
|
||||
(defcustom magit-ediff-dwim-resolve-function #'magit-ediff-resolve-rest
|
||||
"The function `magit-ediff-dwim' uses to resolve conflicts."
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-extras.el --- Additional functionality for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -64,7 +64,7 @@ alternative commands."
|
||||
["Actions"
|
||||
(" m" "Invoke mergetool" magit-git-mergetool)]
|
||||
(interactive
|
||||
(if (and (not (eq transient-current-prefix 'magit-git-mergetool))
|
||||
(if (and (not (eq transient-current-command 'magit-git-mergetool))
|
||||
current-prefix-arg)
|
||||
(list nil nil t)
|
||||
(list (magit-read-unmerged-file "Resolve")
|
||||
@@ -197,27 +197,13 @@ blame to center around the line point is on."
|
||||
(defun ido-enter-magit-status ()
|
||||
"Drop into `magit-status' from file switching.
|
||||
|
||||
This command does not work in Emacs 26.1.
|
||||
See https://github.com/magit/magit/issues/3634
|
||||
and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707.
|
||||
|
||||
To make this command available use something like:
|
||||
|
||||
(add-hook \\='ido-setup-hook
|
||||
(lambda ()
|
||||
(keymap-set ido-completion-map
|
||||
\"C-x g\" \\='ido-enter-magit-status)))
|
||||
|
||||
Starting with Emacs 25.1 the Ido keymaps are defined just once
|
||||
instead of every time Ido is invoked, so now you can modify it
|
||||
like pretty much every other keymap:
|
||||
|
||||
(keymap-set ido-common-completion-map
|
||||
\"C-x g\" \\='ido-enter-magit-status)"
|
||||
(interactive)
|
||||
(setq ido-exit 'fallback)
|
||||
(setq ido-fallback #'magit-status) ; for Emacs >= 26.2
|
||||
(with-no-warnings (setq fallback #'magit-status)) ; for Emacs 25
|
||||
(setq ido-fallback #'magit-status)
|
||||
(exit-minibuffer))
|
||||
|
||||
;;;###autoload
|
||||
@@ -235,10 +221,10 @@ well. If you want to use another key, then you must set this
|
||||
to nil before loading Magit to prevent \"m\" from being bound.")
|
||||
|
||||
(with-eval-after-load 'project
|
||||
;; Only more recent versions of project.el have `project-prefix-map' and
|
||||
;; `project-switch-commands', though project.el is available in Emacs 25.
|
||||
(when (and magit-bind-magit-project-status
|
||||
;; Added in Emacs 28.1.
|
||||
(boundp 'project-prefix-map)
|
||||
(boundp 'project-switch-commands)
|
||||
;; Only modify if it hasn't already been modified.
|
||||
(equal project-switch-commands
|
||||
(eval (car (get 'project-switch-commands 'standard-value))
|
||||
@@ -287,10 +273,7 @@ for a repository."
|
||||
(interactive (list (or (magit-toplevel)
|
||||
(magit-read-repository t))
|
||||
current-prefix-arg))
|
||||
;; Note: The ERROR argument of `dired-get-marked-files' isn't
|
||||
;; available until Emacs 27.
|
||||
(let ((files (or (dired-get-marked-files nil arg)
|
||||
(user-error "No files specified"))))
|
||||
(let ((files (dired-get-marked-files nil arg nil nil t)))
|
||||
(magit-status-setup-buffer repo)
|
||||
(magit-am-apply-patches files)))
|
||||
|
||||
@@ -392,32 +375,28 @@ in HEAD as well as staged changes in the diff to check."
|
||||
(require 'diff-mode) ; `diff-add-log-current-defuns'.
|
||||
(require 'vc-git) ; `vc-git-diff'.
|
||||
(require 'add-log) ; `change-log-insert-entries'.
|
||||
(cond
|
||||
((and (fboundp 'change-log-insert-entries)
|
||||
(fboundp 'diff-add-log-current-defuns))
|
||||
(setq default-directory
|
||||
(if (and (file-regular-p "gitdir")
|
||||
(not (magit-git-true "rev-parse" "--is-inside-work-tree"))
|
||||
(magit-git-true "rev-parse" "--is-inside-git-dir"))
|
||||
(file-name-directory (magit-file-line "gitdir"))
|
||||
(magit-toplevel)))
|
||||
(let ((rev1 (if amending "HEAD^1" "HEAD"))
|
||||
(rev2 nil))
|
||||
;; Magit may have updated the files without notifying vc, but
|
||||
;; `diff-add-log-current-defuns' relies on vc being up-to-date.
|
||||
(mapc #'vc-file-clearprops (magit-staged-files))
|
||||
(change-log-insert-entries
|
||||
(with-temp-buffer
|
||||
(vc-git-command (current-buffer) 1 nil
|
||||
"diff-index" "--exit-code" "--patch"
|
||||
(and (magit-anything-staged-p) "--cached")
|
||||
rev1 "--")
|
||||
;; `diff-find-source-location' consults these vars.
|
||||
(defvar diff-vc-revisions)
|
||||
(setq-local diff-vc-revisions (list rev1 rev2))
|
||||
(setq-local diff-vc-backend 'Git)
|
||||
(diff-add-log-current-defuns)))))
|
||||
(t (user-error "`magit-generate-changelog' requires Emacs 27 or greater"))))
|
||||
(setq default-directory
|
||||
(if (and (file-regular-p "gitdir")
|
||||
(not (magit-git-true "rev-parse" "--is-inside-work-tree"))
|
||||
(magit-git-true "rev-parse" "--is-inside-git-dir"))
|
||||
(file-name-directory (magit-file-line "gitdir"))
|
||||
(magit-toplevel)))
|
||||
(let ((rev1 (if amending "HEAD^1" "HEAD"))
|
||||
(rev2 nil))
|
||||
;; Magit may have updated the files without notifying vc, but
|
||||
;; `diff-add-log-current-defuns' relies on vc being up-to-date.
|
||||
(mapc #'vc-file-clearprops (magit-staged-files))
|
||||
(change-log-insert-entries
|
||||
(with-temp-buffer
|
||||
(vc-git-command (current-buffer) 1 nil
|
||||
"diff-index" "--exit-code" "--patch"
|
||||
(and (magit-anything-staged-p) "--cached")
|
||||
rev1 "--")
|
||||
;; `diff-find-source-location' consults these vars.
|
||||
(defvar diff-vc-revisions)
|
||||
(setq-local diff-vc-revisions (list rev1 rev2))
|
||||
(setq-local diff-vc-backend 'Git)
|
||||
(diff-add-log-current-defuns)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-add-change-log-entry (&optional whoami file-name other-window)
|
||||
@@ -550,7 +529,8 @@ list returned by `magit-rebase-arguments'."
|
||||
((not rev)
|
||||
(when (and (magit-ref-p backup)
|
||||
(not (magit-y-or-n-p
|
||||
(format "Backup ref %s already exists. Override? " backup))))
|
||||
(format "Backup ref %s already exists. Override? "
|
||||
backup))))
|
||||
(user-error "Abort"))
|
||||
(magit-log-select
|
||||
(lambda (rev)
|
||||
@@ -744,8 +724,6 @@ the minibuffer too."
|
||||
(delete-char -1)))))
|
||||
(user-error "Revision stack is empty")))
|
||||
|
||||
(keymap-set git-commit-mode-map "C-c C-w" #'magit-pop-revision-stack)
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-copy-section-value (arg)
|
||||
"Save the value of the current section for later use.
|
||||
@@ -914,6 +892,20 @@ patch application, a cherry-pick, a revert, or a bisect."
|
||||
((magit-sequencer-in-progress-p) (magit-sequencer-abort))
|
||||
((magit-bisect-in-progress-p) (magit-bisect-reset))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-back-to-indentation ()
|
||||
"Move point to the first non-whitespace character on this line.
|
||||
In Magit diffs, also skip over - and + at the beginning of the line."
|
||||
(interactive "^")
|
||||
(beginning-of-line 1)
|
||||
(when (and (magit-section-match 'hunk)
|
||||
(looking-at (if (oref (magit-current-section) combined)
|
||||
"^ ?[-+]+"
|
||||
"^[-+]")))
|
||||
(goto-char (match-end 0)))
|
||||
(skip-syntax-forward " " (line-end-position))
|
||||
(backward-prefix-chars))
|
||||
|
||||
;;; _
|
||||
(provide 'magit-extras)
|
||||
;;; magit-extras.el ends here
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-fetch.el --- Download objects and refs -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
["Arguments"
|
||||
("-p" "Prune deleted branches" ("-p" "--prune"))
|
||||
("-t" "Fetch all tags" ("-t" "--tags"))
|
||||
(7 "-u" "Fetch full history" "--unshallow")]
|
||||
("-u" "Fetch full history" "--unshallow" :level 7)
|
||||
("-F" "Force" ("-f" "--force"))]
|
||||
["Fetch from"
|
||||
("p" magit-fetch-from-pushremote)
|
||||
("u" magit-fetch-from-upstream)
|
||||
@@ -177,11 +178,6 @@ with a prefix argument."
|
||||
(list nil (transient-args 'magit-fetch-modules))))
|
||||
(if transient
|
||||
(transient-setup 'magit-fetch-modules)
|
||||
(when (magit-git-version< "2.8.0")
|
||||
(when-let ((value (transient-arg-value "--jobs=" args)))
|
||||
(message "Dropping --jobs; not supported by Git v%s"
|
||||
(magit-git-version))
|
||||
(setq args (remove (format "--jobs=%s" value) args))))
|
||||
(magit-with-toplevel
|
||||
(magit-run-git-async "fetch" "--recurse-submodules" args))))
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-files.el --- Finding files -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -177,21 +177,22 @@ then only after asking. A non-nil value for REVERT is ignored if REV is
|
||||
(setq buffer-file-coding-system last-coding-system-used))
|
||||
(let ((buffer-file-name magit-buffer-file-name)
|
||||
(after-change-major-mode-hook
|
||||
(remq 'global-diff-hl-mode-enable-in-buffers
|
||||
after-change-major-mode-hook)))
|
||||
(seq-difference after-change-major-mode-hook
|
||||
'(global-diff-hl-mode-enable-in-buffer ; Emacs >= 30
|
||||
global-diff-hl-mode-enable-in-buffers ; Emacs < 30
|
||||
eglot--maybe-activate-editing-mode)
|
||||
#'eq)))
|
||||
(normal-mode t))
|
||||
(setq buffer-read-only t)
|
||||
(set-buffer-modified-p nil)
|
||||
(goto-char (point-min))))
|
||||
|
||||
(defun magit--lsp--disable-when-visiting-blob (fn &rest args)
|
||||
(define-advice lsp (:around (fn &rest args) magit-find-file)
|
||||
"Do nothing when visiting blob using `magit-find-file' and similar.
|
||||
See also https://github.com/doomemacs/doomemacs/pull/6309."
|
||||
(unless magit-buffer-revision
|
||||
(apply fn args)))
|
||||
|
||||
(advice-add 'lsp :around #'magit--lsp--disable-when-visiting-blob)
|
||||
|
||||
;;; Find Index
|
||||
|
||||
(defvar magit-find-index-hook nil)
|
||||
@@ -209,7 +210,7 @@ is done using `magit-find-index-noselect'."
|
||||
(let ((file (magit-file-relative-name)))
|
||||
(unless (equal magit-buffer-refname "{index}")
|
||||
(user-error "%s isn't visiting the index" file))
|
||||
(if (y-or-n-p (format "Update index with contents of %s" (buffer-name)))
|
||||
(if (y-or-n-p (format "Update index with contents of %s?" (buffer-name)))
|
||||
(let ((index (make-temp-name
|
||||
(expand-file-name "magit-update-index-" (magit-gitdir))))
|
||||
(buffer (current-buffer)))
|
||||
@@ -491,7 +492,7 @@ Git, then fallback to using `delete-file'."
|
||||
(interactive
|
||||
(let ((rev (magit-read-branch-or-commit
|
||||
"Checkout from revision" magit-buffer-revision)))
|
||||
(list rev (magit-read-file-from-rev rev "Checkout file"))))
|
||||
(list rev (magit-read-file-from-rev rev "Checkout file" nil t))))
|
||||
(magit-with-toplevel
|
||||
(magit-run-git "checkout" rev "--" file)))
|
||||
|
||||
@@ -499,8 +500,11 @@ Git, then fallback to using `delete-file'."
|
||||
|
||||
(defvar magit-read-file-hist nil)
|
||||
|
||||
(defun magit-read-file-from-rev (rev prompt &optional default)
|
||||
(defun magit-read-file-from-rev (rev prompt &optional default include-dirs)
|
||||
(let ((files (magit-revision-files rev)))
|
||||
(when include-dirs
|
||||
(setq files (sort (nconc files (magit-revision-directories rev))
|
||||
#'string<)))
|
||||
(magit-completing-read
|
||||
prompt files nil t nil 'magit-read-file-hist
|
||||
(car (member (or default (magit-current-file)) files)))))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
;;; magit-gitignore.el --- Intentionally untracked files -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -116,11 +116,12 @@ Rules that are defined in that file affect all local repositories."
|
||||
(base (and base (file-directory-p base) base))
|
||||
(choices
|
||||
(delete-dups
|
||||
(--mapcat
|
||||
(cons (concat "/" it)
|
||||
(and-let* ((ext (file-name-extension it)))
|
||||
(list (concat "/" (file-name-directory it) "*." ext)
|
||||
(concat "*." ext))))
|
||||
(mapcan
|
||||
(lambda (file)
|
||||
(cons (concat "/" file)
|
||||
(and-let* ((ext (file-name-extension file)))
|
||||
(list (concat "/" (file-name-directory file) "*." ext)
|
||||
(concat "*." ext)))))
|
||||
(sort (nconc
|
||||
(magit-untracked-files nil base)
|
||||
;; The untracked section of the status buffer lists
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-log.el --- Inspect Git history -*- lexical-binding:t; coding:utf-8 -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
(declare-function magit-insert-upstream-branch-header "magit-status"
|
||||
(&optional branch pull keyword))
|
||||
(declare-function magit-read-file-from-rev "magit-files"
|
||||
(rev prompt &optional default))
|
||||
(rev prompt &optional default include-dirs))
|
||||
(declare-function magit-rebase--get-state-lines "magit-sequence"
|
||||
(file))
|
||||
(declare-function magit-show-commit "magit-diff"
|
||||
@@ -55,6 +55,14 @@
|
||||
(require 'crm)
|
||||
(require 'which-func)
|
||||
|
||||
(make-obsolete-variable 'magit-log-highlight-keywords
|
||||
'magit-log-wash-summary-hook
|
||||
"Magit 4.3.0")
|
||||
|
||||
(make-obsolete-variable 'magit-log-format-message-function
|
||||
'magit-log-wash-summary-hook
|
||||
"Magit 4.3.0")
|
||||
|
||||
;;; Options
|
||||
;;;; Log Mode
|
||||
|
||||
@@ -143,18 +151,30 @@ This is useful if you use really long branch names."
|
||||
:group 'magit-log
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom magit-log-highlight-keywords t
|
||||
"Whether to highlight bracketed keywords in commit summaries."
|
||||
:package-version '(magit . "2.12.0")
|
||||
(defcustom magit-log-wash-summary-hook
|
||||
(list #'magit-highlight-squash-markers
|
||||
#'magit-highlight-bracket-keywords)
|
||||
"Functions used to highlight parts of each individual commit summary.
|
||||
|
||||
These functions are called in order, in a buffer that containing the
|
||||
first line of the commit message. They should set text properties as
|
||||
they see fit, usually just `font-lock-face'. Before each function is
|
||||
called, point is at the beginning of the buffer.
|
||||
|
||||
See also the related `magit-revision-wash-message-hook'. You likely
|
||||
want to use the same functions for both hooks."
|
||||
:package-version '(magit . "4.3.0")
|
||||
:group 'magit-log
|
||||
:type 'boolean)
|
||||
:type 'hook
|
||||
:options (list #'magit-highlight-squash-markers
|
||||
#'magit-highlight-bracket-keywords))
|
||||
|
||||
(defcustom magit-log-header-line-function #'magit-log-header-line-sentence
|
||||
"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)
|
||||
:type `(choice (function-item ,#'magit-log-header-line-arguments)
|
||||
(function-item ,#'magit-log-header-line-sentence)
|
||||
function))
|
||||
|
||||
(defcustom magit-log-trace-definition-function #'magit-which-function
|
||||
@@ -164,9 +184,9 @@ 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)
|
||||
:type `(choice (function-item ,#'magit-which-function)
|
||||
(function-item ,#'which-function)
|
||||
(function-item ,#'add-log-current-defun)
|
||||
function))
|
||||
|
||||
(defcustom magit-log-color-graph-limit 256
|
||||
@@ -280,8 +300,8 @@ AUTHOR-WIDTH has to be an integer. When the name of the author
|
||||
;;;; Cherry Mode
|
||||
|
||||
(defcustom magit-cherry-sections-hook
|
||||
'(magit-insert-cherry-headers
|
||||
magit-insert-cherry-commits)
|
||||
(list #'magit-insert-cherry-headers
|
||||
#'magit-insert-cherry-commits)
|
||||
"Hook run to insert sections into the cherry buffer."
|
||||
:package-version '(magit . "2.1.0")
|
||||
:group 'magit-log
|
||||
@@ -353,15 +373,15 @@ commits before and half after."
|
||||
(pcase-let ((`(,args ,files)
|
||||
(magit-log--get-value 'magit-log-mode
|
||||
magit-prefix-use-buffer-arguments)))
|
||||
(unless (eq transient-current-command 'magit-dispatch)
|
||||
(when-let ((file (magit-file-relative-name)))
|
||||
(setq files (list file))))
|
||||
(oset obj value (if files `(("--" ,@files) ,args) args))))
|
||||
(when-let (((not (eq transient-current-command 'magit-dispatch)))
|
||||
(file (magit-file-relative-name)))
|
||||
(setq files (list file)))
|
||||
(oset obj value (if files `(("--" ,@files) ,@args) args))))
|
||||
|
||||
(cl-defmethod transient-init-value ((obj magit-log-refresh-prefix))
|
||||
(oset obj value (if magit-buffer-log-files
|
||||
`(("--" ,@magit-buffer-log-files)
|
||||
,magit-buffer-log-args)
|
||||
,@magit-buffer-log-args)
|
||||
magit-buffer-log-args)))
|
||||
|
||||
(cl-defmethod transient-set-value ((obj magit-log-prefix))
|
||||
@@ -387,13 +407,13 @@ commits before and half after."
|
||||
(eq major-mode mode))
|
||||
(setq args magit-buffer-log-args)
|
||||
(setq files magit-buffer-log-files))
|
||||
((and (memq use-buffer-args '(always selected))
|
||||
(when-let ((buffer (magit-get-mode-buffer
|
||||
mode nil
|
||||
(eq use-buffer-args 'selected))))
|
||||
(setq args (buffer-local-value 'magit-buffer-log-args buffer))
|
||||
(setq files (buffer-local-value 'magit-buffer-log-files buffer))
|
||||
t)))
|
||||
((when-let (((memq use-buffer-args '(always selected)))
|
||||
(buffer (magit-get-mode-buffer
|
||||
mode nil
|
||||
(eq use-buffer-args 'selected))))
|
||||
(setq args (buffer-local-value 'magit-buffer-log-args buffer))
|
||||
(setq files (buffer-local-value 'magit-buffer-log-files buffer))
|
||||
t))
|
||||
((plist-member (symbol-plist mode) 'magit-log-current-arguments)
|
||||
(setq args (get mode 'magit-log-current-arguments)))
|
||||
((when-let ((elt (assq (intern (format "magit-log:%s" mode))
|
||||
@@ -422,51 +442,57 @@ 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
|
||||
]))
|
||||
|
||||
;;;###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
|
||||
;; 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"
|
||||
(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
|
||||
[magit-log-infix-arguments]
|
||||
[["Log"
|
||||
("l" "current" magit-log-current)
|
||||
("h" "HEAD" magit-log-head)
|
||||
@@ -498,36 +524,7 @@ commits before and half after."
|
||||
:man-page "git-log"
|
||||
:class 'magit-log-refresh-prefix
|
||||
[:if-mode magit-log-mode
|
||||
:class transient-subgroups
|
||||
["Commit limiting"
|
||||
(magit-log:-n)
|
||||
(magit:--author)
|
||||
(magit-log:--grep)
|
||||
(7 "-i" "Search case-insensitive" ("-i" "--regexp-ignore-case"))
|
||||
(7 "-I" "Invert search pattern" "--invert-grep")
|
||||
(magit-log:-G)
|
||||
(magit-log:-S)
|
||||
(magit-log:-L)]
|
||||
["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")
|
||||
("-c" "Show graph in color" "--color")
|
||||
("-d" "Show refnames" "--decorate")
|
||||
("=S" "Show signatures" "--show-signature")
|
||||
("-h" "Show header" "++header")
|
||||
("-p" "Show diffs" ("-p" "--patch"))
|
||||
("-s" "Show diffstats" "--stat")]]
|
||||
magit-log-infix-arguments]
|
||||
[:if-not-mode magit-log-mode
|
||||
:description "Arguments"
|
||||
(magit-log:-n)
|
||||
@@ -540,10 +537,10 @@ commits before and half after."
|
||||
("s" "buffer and set defaults" transient-set-and-exit)
|
||||
("w" "buffer and save defaults" transient-save-and-exit)]
|
||||
["Margin"
|
||||
("L" "toggle visibility" magit-toggle-margin :transient t)
|
||||
("l" "cycle style" magit-cycle-margin-style :transient t)
|
||||
("d" "toggle details" magit-toggle-margin-details :transient t)
|
||||
("x" "toggle shortstat" magit-toggle-log-margin-style :transient t)]
|
||||
(magit-toggle-margin)
|
||||
(magit-cycle-margin-style)
|
||||
(magit-toggle-margin-details)
|
||||
(magit-toggle-log-margin-style)]
|
||||
[:if-mode magit-log-mode
|
||||
:description "Toggle"
|
||||
("b" "buffer lock" magit-toggle-buffer-lock)]]
|
||||
@@ -685,16 +682,16 @@ previously checked out branch and its upstream and push-target."
|
||||
(setq rebase (magit-ref-abbrev rebase))
|
||||
(setq current rebase)
|
||||
(setq head "HEAD"))
|
||||
(t (setq current (magit-get-previous-branch)))))
|
||||
((setq current (magit-get-previous-branch)))))
|
||||
(cond (current
|
||||
(setq current
|
||||
(magit--propertize-face current'magit-branch-local))
|
||||
(magit--propertize-face current 'magit-branch-local))
|
||||
(setq target (magit-get-push-branch current t))
|
||||
(setq upstream (magit-get-upstream-branch current))
|
||||
(when upstream
|
||||
(setq upup (and (magit-local-branch-p upstream)
|
||||
(magit-get-upstream-branch upstream)))))
|
||||
(t (setq head "HEAD")))
|
||||
((setq head "HEAD")))
|
||||
(delq nil (list current head target upstream upup)))
|
||||
(magit-log-arguments)))
|
||||
(magit-log-setup-buffer revs args files))
|
||||
@@ -759,20 +756,7 @@ completion candidates."
|
||||
With a prefix argument or when `--follow' is an active log
|
||||
argument, then follow renames. When the region is active,
|
||||
restrict the log to the lines that the region touches."
|
||||
(interactive
|
||||
(cons current-prefix-arg
|
||||
(and (region-active-p)
|
||||
(magit-file-relative-name)
|
||||
(save-restriction
|
||||
(widen)
|
||||
(list (line-number-at-pos (region-beginning))
|
||||
(line-number-at-pos
|
||||
(let ((end (region-end)))
|
||||
(if (char-after end)
|
||||
end
|
||||
;; Ensure that we don't get the line number
|
||||
;; of a trailing newline.
|
||||
(1- end)))))))))
|
||||
(interactive (cons current-prefix-arg (magit-file-region-line-numbers)))
|
||||
(require 'magit)
|
||||
(if-let ((file (magit-file-relative-name)))
|
||||
(magit-log-setup-buffer
|
||||
@@ -782,9 +766,7 @@ restrict the log to the lines that the region touches."
|
||||
(let ((args (car (magit-log-arguments))))
|
||||
(when (and follow (not (member "--follow" args)))
|
||||
(push "--follow" args))
|
||||
(when (and (file-regular-p
|
||||
(expand-file-name file (magit-toplevel)))
|
||||
beg end)
|
||||
(when (and beg end)
|
||||
(setq args (cons (format "-L%s,%s:%s" beg end file)
|
||||
(cl-delete "-L" args :test
|
||||
#'string-prefix-p)))
|
||||
@@ -901,7 +883,7 @@ limit. Otherwise set it to 256."
|
||||
|
||||
(defun magit-log-set-commit-limit (fn)
|
||||
(let* ((val magit-buffer-log-args)
|
||||
(arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val))
|
||||
(arg (seq-find (##string-match "^-n\\([0-9]+\\)?$" %) val))
|
||||
(num (and arg (string-to-number (match-string 1 arg))))
|
||||
(num (if num (funcall fn num 2) 256)))
|
||||
(setq val (remove arg val))
|
||||
@@ -912,8 +894,8 @@ limit. Otherwise set it to 256."
|
||||
(magit-refresh))
|
||||
|
||||
(defun magit-log-get-commit-limit (&optional args)
|
||||
(and-let* ((str (--first (string-match "^-n\\([0-9]+\\)?$" it)
|
||||
(or args magit-buffer-log-args))))
|
||||
(and-let* ((str (seq-find (##string-match "^-n\\([0-9]+\\)?$" %)
|
||||
(or args magit-buffer-log-args))))
|
||||
(string-to-number (match-string 1 str))))
|
||||
|
||||
;;;; Mode Commands
|
||||
@@ -938,20 +920,19 @@ is displayed in the current frame."
|
||||
(defun magit-log-move-to-parent (&optional n)
|
||||
"Move to the Nth parent of the current commit."
|
||||
(interactive "p")
|
||||
(when (derived-mode-p 'magit-log-mode)
|
||||
(when (magit-section-match 'commit)
|
||||
(let* ((section (magit-current-section))
|
||||
(parent-rev (format "%s^%s" (oref section value) (or n 1))))
|
||||
(if-let ((parent-hash (magit-rev-parse "--short" parent-rev)))
|
||||
(if-let ((parent (--first (equal (oref it value)
|
||||
parent-hash)
|
||||
(magit-section-siblings section 'next))))
|
||||
(magit-section-goto parent)
|
||||
(user-error
|
||||
(substitute-command-keys
|
||||
(concat "Parent " parent-hash " not found. Try typing "
|
||||
"\\[magit-log-double-commit-limit] first"))))
|
||||
(user-error "Parent %s does not exist" parent-rev))))))
|
||||
(when (and (derived-mode-p 'magit-log-mode)
|
||||
(magit-section-match 'commit))
|
||||
(let* ((section (magit-current-section))
|
||||
(parent-rev (format "%s^%s" (oref section value) (or n 1))))
|
||||
(if-let ((parent-hash (magit-rev-parse "--short" parent-rev)))
|
||||
(if-let ((parent (seq-find (##equal (oref % value) parent-hash)
|
||||
(magit-section-siblings section 'next))))
|
||||
(magit-section-goto parent)
|
||||
(user-error
|
||||
(substitute-command-keys
|
||||
(concat "Parent " parent-hash " not found. Try typing "
|
||||
"\\[magit-log-double-commit-limit] first"))))
|
||||
(user-error "Parent %s does not exist" parent-rev)))))
|
||||
|
||||
(defun magit-log-move-to-revision (rev)
|
||||
"Read a revision and move to it in current log buffer.
|
||||
@@ -962,7 +943,15 @@ nothing else.
|
||||
|
||||
If invoked outside any log buffer, then display the log buffer
|
||||
of the current repository first; creating it if necessary."
|
||||
(interactive (list (magit-read-branch-or-commit "In log, jump to")))
|
||||
(interactive
|
||||
(list (or (magit-completing-read
|
||||
"In log, jump to"
|
||||
(magit-list-refnames nil t)
|
||||
nil nil nil 'magit-revision-history
|
||||
(or (and-let* ((rev (magit-commit-at-point)))
|
||||
(magit-rev-fixup-target rev))
|
||||
(magit-get-current-branch)))
|
||||
(user-error "Nothing selected"))))
|
||||
(with-current-buffer
|
||||
(cond ((derived-mode-p 'magit-log-mode)
|
||||
(current-buffer))
|
||||
@@ -1019,6 +1008,59 @@ of the current repository first; creating it if necessary."
|
||||
(transient-args 'magit-shortlog)))
|
||||
(magit-git-shortlog rev-or-range args))
|
||||
|
||||
;;;; Movement Commands
|
||||
|
||||
(defvar magit-reference-movement-faces
|
||||
'(magit-tag
|
||||
magit-branch-remote
|
||||
magit-branch-remote-head
|
||||
magit-branch-local
|
||||
magit-branch-current
|
||||
magit-branch-upstream
|
||||
magit-branch-warning
|
||||
magit-head
|
||||
magit-refname
|
||||
magit-refname-stash
|
||||
magit-refname-wip
|
||||
magit-refname-pullreq))
|
||||
|
||||
(defvar-keymap magit-reference-navigation-repeat-map
|
||||
:repeat t
|
||||
"p" #'magit-previous-reference
|
||||
"n" #'magit-next-reference
|
||||
"r" #'magit-next-reference)
|
||||
|
||||
(defun magit-previous-reference ()
|
||||
"Move to the previous Git reference appearing in the current buffer.
|
||||
|
||||
Move to the previous location that uses a face appearing in
|
||||
`magit-reference-movement-faces'. If `repeat-mode' is enabled,
|
||||
this command and its counterpart can be repeated using \
|
||||
\\<magit-reference-navigation-repeat-map>\
|
||||
\\[magit-previous-reference] and \\[magit-next-reference]."
|
||||
(interactive)
|
||||
(magit-next-reference t))
|
||||
|
||||
(defun magit-next-reference (&optional previous)
|
||||
"Move to the next Git reference appearing in the current buffer.
|
||||
|
||||
Move to the next location that uses a face appearing in
|
||||
`magit-reference-movement-faces'. If `repeat-mode' is enabled,
|
||||
this command and its counterpart can be repeated using \
|
||||
\\<magit-reference-navigation-repeat-map>\
|
||||
\\[magit-previous-reference] and \\[magit-next-reference]."
|
||||
(interactive)
|
||||
(catch 'found
|
||||
(let ((pos (point)))
|
||||
(while (and (not (eobp))
|
||||
(setq pos (if previous
|
||||
(previous-single-property-change pos 'face)
|
||||
(next-single-property-change pos 'face))))
|
||||
(when (cl-intersection (ensure-list (get-text-property pos 'face))
|
||||
magit-reference-movement-faces)
|
||||
(throw 'found (goto-char pos))))
|
||||
(message "No more references"))))
|
||||
|
||||
;;; Log Mode
|
||||
|
||||
(defvar magit-log-disable-graph-hack-args
|
||||
@@ -1053,8 +1095,9 @@ Type \\[magit-cherry-pick] to apply the commit at point.
|
||||
Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
|
||||
\\{magit-log-mode-map}"
|
||||
:interactive nil
|
||||
:group 'magit-log
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(magit-hack-dir-local-variables)
|
||||
(setq magit--imenu-item-types 'commit))
|
||||
|
||||
(put 'magit-log-mode 'magit-log-default-arguments
|
||||
@@ -1083,9 +1126,8 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
(unless (length= files 1)
|
||||
(setq args (remove "--follow" args)))
|
||||
(when (and (car magit-log-remove-graph-args)
|
||||
(--any-p (string-match-p
|
||||
(concat "^" (regexp-opt magit-log-remove-graph-args)) it)
|
||||
args))
|
||||
(let ((re (concat "^" (regexp-opt magit-log-remove-graph-args))))
|
||||
(seq-some (##string-match-p re %) args)))
|
||||
(setq args (remove "--graph" args)))
|
||||
(setq args (magit-log--maybe-drop-color-graph args limit))
|
||||
(when-let* ((limit limit)
|
||||
@@ -1097,8 +1139,8 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
(not (member revs '("--all" "--branches")))
|
||||
(not (seq-some
|
||||
(lambda (arg)
|
||||
(--any-p (string-prefix-p it arg)
|
||||
magit-log-disable-graph-hack-args))
|
||||
(seq-some (##string-prefix-p % arg)
|
||||
magit-log-disable-graph-hack-args))
|
||||
args))
|
||||
(magit-git-string "rev-list" "--count"
|
||||
"--first-parent" args revs))))
|
||||
@@ -1149,14 +1191,14 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
(defun magit-log-header-line-sentence (revs args files)
|
||||
"Return string containing all arguments."
|
||||
(concat "Commits in "
|
||||
(mapconcat #'identity revs " ")
|
||||
(string-join revs " ")
|
||||
(and (member "--reverse" args)
|
||||
" in reverse")
|
||||
(and files (concat " touching "
|
||||
(mapconcat #'identity files " ")))
|
||||
(--some (and (string-prefix-p "-L" it)
|
||||
(concat " " it))
|
||||
args)))
|
||||
(string-join files " ")))
|
||||
(seq-some (##and (string-prefix-p "-L" %)
|
||||
(concat " " %))
|
||||
args)))
|
||||
|
||||
(defun magit-insert-log (revs &optional args files)
|
||||
(declare (obsolete magit--insert-log "Magit 4.0.0"))
|
||||
@@ -1200,8 +1242,8 @@ Do not add this to a hook variable."
|
||||
(concat "\n" magit-log-revision-headers-format "\n"))
|
||||
""))
|
||||
(progn
|
||||
(when-let ((order (--first (string-match "^\\+\\+order=\\(.+\\)$" it)
|
||||
args)))
|
||||
(when-let ((order (seq-find (##string-match "^\\+\\+order=\\(.+\\)$" %)
|
||||
args)))
|
||||
(setq args (cons (format "--%s-order" (match-string 1 order))
|
||||
(remove order args))))
|
||||
(when (member "--decorate" args)
|
||||
@@ -1292,8 +1334,6 @@ Do not add this to a hook variable."
|
||||
|
||||
(defvar magit-log-count nil)
|
||||
|
||||
(defvar magit-log-format-message-function #'magit-log-propertize-keywords)
|
||||
|
||||
(defun magit-log-wash-log (style args)
|
||||
(setq args (flatten-tree args))
|
||||
(when (if (derived-mode-p 'magit-log-mode)
|
||||
@@ -1353,12 +1393,16 @@ Do not add this to a hook variable."
|
||||
;; of the youngest expired reflog entry.
|
||||
(when (and (eq style 'reflog) (not date))
|
||||
(cl-return-from magit-log-wash-rev t))
|
||||
(magit-insert-section section (commit hash)
|
||||
(pcase style
|
||||
('stash (oset section type 'stash))
|
||||
('module (oset section type 'module-commit))
|
||||
('bisect-log (setq hash (magit-rev-parse "--short" hash))))
|
||||
(setq hash (propertize hash 'font-lock-face
|
||||
(magit-insert-section
|
||||
((eval (pcase style
|
||||
('stash 'stash)
|
||||
('module 'module-commit)
|
||||
(_ 'commit)))
|
||||
hash)
|
||||
(setq hash (propertize (if (eq style 'bisect-log)
|
||||
(magit-rev-parse "--short" hash)
|
||||
hash)
|
||||
'font-lock-face
|
||||
(pcase (and gpg (aref gpg 0))
|
||||
(?G 'magit-signature-good)
|
||||
(?B 'magit-signature-bad)
|
||||
@@ -1398,7 +1442,7 @@ Do not add this to a hook variable."
|
||||
(insert (magit-reflog-format-subject
|
||||
(substring refsub 0
|
||||
(if (string-search ":" refsub) -2 -1))))))
|
||||
(insert (funcall magit-log-format-message-function hash msg))
|
||||
(insert (magit-log--wash-summary msg))
|
||||
(when (and refs magit-log-show-refname-after-summary)
|
||||
(insert ?\s)
|
||||
(insert (magit-format-ref-labels refs)))
|
||||
@@ -1462,18 +1506,12 @@ Do not add this to a hook variable."
|
||||
(insert graph ?\n))))))))
|
||||
t)
|
||||
|
||||
(defun magit-log-propertize-keywords (_rev msg)
|
||||
(let ((boundary 0))
|
||||
(when (string-match "^\\(?:squash\\|fixup\\)! " msg boundary)
|
||||
(setq boundary (match-end 0))
|
||||
(magit--put-face (match-beginning 0) (1- boundary)
|
||||
'magit-keyword-squash msg))
|
||||
(when magit-log-highlight-keywords
|
||||
(while (string-match "\\[[^][]*]" msg boundary)
|
||||
(setq boundary (match-end 0))
|
||||
(magit--put-face (match-beginning 0) boundary
|
||||
'magit-keyword msg))))
|
||||
msg)
|
||||
(defun magit-log--wash-summary (summary)
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert summary))
|
||||
(run-hook-wrapped 'magit-log-wash-summary-hook
|
||||
(lambda (fn) (prog1 nil (save-excursion (funcall fn)))))
|
||||
(buffer-string)))
|
||||
|
||||
(defun magit-log-maybe-show-more-commits (section)
|
||||
"When point is at the end of a log buffer, insert more commits.
|
||||
@@ -1531,10 +1569,10 @@ If there is no blob buffer in the same frame, then do nothing."
|
||||
|
||||
(defun magit--maybe-update-blob-buffer ()
|
||||
(when-let* ((commit (magit-section-value-if 'commit))
|
||||
(buffer (--first (with-current-buffer it
|
||||
(eq revert-buffer-function
|
||||
'magit-revert-rev-file-buffer))
|
||||
(mapcar #'window-buffer (window-list)))))
|
||||
(buffer (seq-find (##with-current-buffer %
|
||||
(eq revert-buffer-function
|
||||
'magit-revert-rev-file-buffer))
|
||||
(mapcar #'window-buffer (window-list)))))
|
||||
(if magit--update-blob-buffer
|
||||
(setq magit--update-blob-buffer (list commit buffer))
|
||||
(setq magit--update-blob-buffer (list commit buffer))
|
||||
@@ -1553,8 +1591,8 @@ If there is no blob buffer in the same frame, then do nothing."
|
||||
|
||||
(defun magit-log-goto-commit-section (rev)
|
||||
(let ((abbrev (magit-rev-format "%h" rev)))
|
||||
(when-let ((section (--first (equal (oref it value) abbrev)
|
||||
(oref magit-root-section children))))
|
||||
(when-let ((section (seq-find (##equal (oref % value) abbrev)
|
||||
(oref magit-root-section children))))
|
||||
(goto-char (oref section start)))))
|
||||
|
||||
(defun magit-log-goto-same-commit ()
|
||||
@@ -1567,9 +1605,12 @@ If there is no blob buffer in the same frame, then do nothing."
|
||||
|
||||
(defvar-local magit-log-margin-show-shortstat nil)
|
||||
|
||||
(defun magit-toggle-log-margin-style ()
|
||||
(transient-define-suffix magit-toggle-log-margin-style ()
|
||||
"Toggle between the regular and the shortstat margin style.
|
||||
The shortstat style is experimental and rather slow."
|
||||
:description "Toggle shortstat"
|
||||
:key "x"
|
||||
:transient t
|
||||
(interactive)
|
||||
(setq magit-log-margin-show-shortstat
|
||||
(not magit-log-margin-show-shortstat))
|
||||
@@ -1584,7 +1625,8 @@ The shortstat style is experimental and rather slow."
|
||||
(defun magit-log-format-author-margin (author date &optional previous-line)
|
||||
(pcase-let ((`(,_ ,style ,width ,details ,details-width)
|
||||
(or magit-buffer-margin
|
||||
(symbol-value (magit-margin-option)))))
|
||||
(symbol-value (magit-margin-option))
|
||||
(error "No margin format specified for %s" major-mode))))
|
||||
(magit-make-margin-overlay
|
||||
(concat (and details
|
||||
(concat (magit--propertize-face
|
||||
@@ -1642,9 +1684,9 @@ The shortstat style is experimental and rather slow."
|
||||
(if (eq style 'age-abbreviated)
|
||||
1 ; single character
|
||||
(+ 1 ; gap after digits
|
||||
(apply #'max (--map (max (length (nth 1 it))
|
||||
(length (nth 2 it)))
|
||||
magit--age-spec)))))))))
|
||||
(apply #'max (mapcar (##max (length (nth 1 %))
|
||||
(length (nth 2 %)))
|
||||
magit--age-spec)))))))))
|
||||
|
||||
;;; Select Mode
|
||||
|
||||
@@ -1675,7 +1717,7 @@ to visit the commit at point.
|
||||
Type \\[magit-log-select-pick] to select the commit at point.
|
||||
Type \\[magit-log-select-quit] to abort without selecting a commit."
|
||||
:group 'magit-log
|
||||
(hack-dir-local-variables-non-file-buffer))
|
||||
(magit-hack-dir-local-variables))
|
||||
|
||||
(put 'magit-log-select-mode 'magit-log-default-arguments
|
||||
'("--graph" "-n256" "--decorate"))
|
||||
@@ -1709,8 +1751,14 @@ Type \\[magit-log-select-quit] to abort without selecting a commit."
|
||||
(append args
|
||||
(car (magit-log--get-value 'magit-log-select-mode
|
||||
magit-direct-use-buffer-arguments))))
|
||||
(when initial
|
||||
(magit-log-goto-commit-section initial))
|
||||
(if initial
|
||||
(magit-log-goto-commit-section initial)
|
||||
(while-let ((rev (magit-section-value-if 'commit))
|
||||
((string-match-p "\\`\\(squash!\\|fixup!\\|amend!\\)"
|
||||
(magit-rev-format "%s" rev)))
|
||||
(section (magit-current-section))
|
||||
(next (car (magit-section-siblings section 'next))))
|
||||
(magit-section-goto next)))
|
||||
(setq magit-log-select-pick-function pick)
|
||||
(setq magit-log-select-quit-function quit)
|
||||
(when magit-log-select-show-usage
|
||||
@@ -1774,8 +1822,9 @@ to visit the commit at point.
|
||||
Type \\[magit-cherry-pick] to apply the commit at point.
|
||||
|
||||
\\{magit-cherry-mode-map}"
|
||||
:interactive nil
|
||||
:group 'magit-log
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(magit-hack-dir-local-variables)
|
||||
(setq magit--imenu-group-types 'cherries))
|
||||
|
||||
(defun magit-cherry-setup-buffer (head upstream)
|
||||
@@ -1785,7 +1834,6 @@ Type \\[magit-cherry-pick] to apply the commit at point.
|
||||
(magit-buffer-range (concat upstream ".." head))))
|
||||
|
||||
(defun magit-cherry-refresh-buffer ()
|
||||
(setq magit-section-inhibit-markers t)
|
||||
(setq magit-section-insert-in-reverse t)
|
||||
(magit-insert-section (cherry)
|
||||
(magit-run-section-hook 'magit-cherry-sections-hook)))
|
||||
@@ -1818,7 +1866,7 @@ Type \\[magit-cherry-pick] to apply the commit at point.
|
||||
(defun magit-insert-cherry-commits ()
|
||||
"Insert commit sections into a `magit-cherry-mode' buffer."
|
||||
(magit-insert-section (cherries)
|
||||
(magit-insert-heading "Cherry commits:")
|
||||
(magit-insert-heading t "Cherry commits")
|
||||
(magit-git-wash (apply-partially #'magit-log-wash-log 'cherry)
|
||||
"cherry" "-v" "--abbrev"
|
||||
magit-buffer-upstream
|
||||
@@ -1835,21 +1883,18 @@ keymap is the parent of their keymaps."
|
||||
"<remap> <magit-visit-thing>" #'magit-diff-dwim
|
||||
"<1>" (magit-menu-item "Visit diff" #'magit-diff-dwim))
|
||||
|
||||
(defvar-keymap magit-unpulled-section-map
|
||||
:doc "Keymap for `unpulled' sections."
|
||||
:parent magit-log-section-map)
|
||||
|
||||
(cl-defmethod magit-section-ident-value ((section magit-unpulled-section))
|
||||
"\"..@{push}\" cannot be used as the value because that is
|
||||
ambiguous if `push.default' does not allow a 1:1 mapping, and
|
||||
many commands would fail because of that. But here that does
|
||||
not matter and we need an unique value so we use that string
|
||||
in the pushremote case."
|
||||
"Return \"..@{push}\".
|
||||
\"..@{push}\" cannot be used as the value because that is ambiguous
|
||||
if `push.default' does not allow a 1:1 mapping, and many commands
|
||||
would fail because of that. But here that does not matter and we
|
||||
need an unique value, so we use that string in the pushremote case."
|
||||
(let ((value (oref section value)))
|
||||
(if (equal value "..@{upstream}") value "..@{push}")))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-unpulled-from-upstream
|
||||
"Unpulled from @{upstream}" unpulled "..@{upstream}")
|
||||
"Unpulled from @{upstream}" unpulled "..@{upstream}"
|
||||
magit-insert-unpulled-from-upstream)
|
||||
|
||||
(defun magit-insert-unpulled-from-upstream ()
|
||||
"Insert commits that haven't been pulled from the upstream yet."
|
||||
@@ -1863,36 +1908,44 @@ in the pushremote case."
|
||||
(magit-log-insert-child-count))))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote
|
||||
"Unpulled from <push-remote>" unpulled "..@{push}")
|
||||
"Unpulled from <push-remote>" unpulled "..@{push}"
|
||||
magit-insert-unpulled-from-pushremote)
|
||||
|
||||
(defun magit-insert-unpulled-from-pushremote ()
|
||||
"Insert commits that haven't been pulled from the push-remote yet."
|
||||
(when-let* ((target (magit-get-push-branch))
|
||||
(range (concat ".." target)))
|
||||
(when (magit--insert-pushremote-log-p)
|
||||
(magit-insert-section (unpulled range t)
|
||||
(magit-insert-heading
|
||||
(format (propertize "Unpulled from %s."
|
||||
'font-lock-face 'magit-section-heading)
|
||||
(propertize target 'font-lock-face 'magit-branch-remote)))
|
||||
(magit--insert-log nil range magit-buffer-log-args)
|
||||
(magit-log-insert-child-count)))))
|
||||
|
||||
(defvar-keymap magit-unpushed-section-map
|
||||
:doc "Keymap for `unpushed' sections."
|
||||
:parent magit-log-section-map)
|
||||
(range (concat ".." target))
|
||||
((magit--insert-pushremote-log-p)))
|
||||
(magit-insert-section (unpulled range t)
|
||||
(magit-insert-heading
|
||||
(format (propertize "Unpulled from %s."
|
||||
'font-lock-face 'magit-section-heading)
|
||||
(propertize target 'font-lock-face 'magit-branch-remote)))
|
||||
(magit--insert-log nil range magit-buffer-log-args)
|
||||
(magit-log-insert-child-count))))
|
||||
|
||||
(cl-defmethod magit-section-ident-value ((section magit-unpushed-section))
|
||||
"\"..@{push}\" cannot be used as the value because that is
|
||||
ambiguous if `push.default' does not allow a 1:1 mapping, and
|
||||
many commands would fail because of that. But here that does
|
||||
not matter and we need an unique value so we use that string
|
||||
in the pushremote case."
|
||||
"Return \"..@{push}\".
|
||||
\"..@{push}\" cannot be used as the value because that is ambiguous
|
||||
if `push.default' does not allow a 1:1 mapping, and many commands
|
||||
would fail because of that. But here that does not matter and we
|
||||
need an unique value, so we use that string in the pushremote case."
|
||||
(let ((value (oref section value)))
|
||||
(if (equal value "@{upstream}..") value "@{push}..")))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-unpushed-to-upstream
|
||||
"Unpushed to @{upstream}" unpushed "@{upstream}..")
|
||||
"Unpushed to @{upstream}" unpushed "@{upstream}.." nil
|
||||
:if (lambda ()
|
||||
(or (memq 'magit-insert-unpushed-to-upstream-or-recent
|
||||
magit-status-sections-hook)
|
||||
(memq 'magit-insert-unpushed-to-upstream
|
||||
magit-status-sections-hook)))
|
||||
:description (lambda ()
|
||||
(let ((upstream (magit-get-upstream-branch)))
|
||||
(if (or (not upstream)
|
||||
(magit-rev-ancestor-p "HEAD" upstream))
|
||||
"Recent commits"
|
||||
"Unmerged into upstream"))))
|
||||
|
||||
(defun magit-insert-unpushed-to-upstream-or-recent ()
|
||||
"Insert section showing unpushed or other recent commits.
|
||||
@@ -1928,26 +1981,28 @@ Show the last `magit-log-section-commit-count' commits."
|
||||
(or value range)
|
||||
t)
|
||||
(magit-insert-heading "Recent commits")
|
||||
(magit--insert-log nil range
|
||||
(magit--insert-log nil
|
||||
(and (member "--graph" magit-buffer-log-args) range)
|
||||
(cons (format "-n%d" magit-log-section-commit-count)
|
||||
(--remove (string-prefix-p "-n" it)
|
||||
magit-buffer-log-args))))))
|
||||
(seq-remove (##string-prefix-p "-n" %)
|
||||
magit-buffer-log-args))))))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote
|
||||
"Unpushed to <push-remote>" unpushed "@{push}..")
|
||||
"Unpushed to <push-remote>" unpushed "@{push}.."
|
||||
magit-insert-unpushed-to-pushremote)
|
||||
|
||||
(defun magit-insert-unpushed-to-pushremote ()
|
||||
"Insert commits that haven't been pushed to the push-remote yet."
|
||||
(when-let* ((target (magit-get-push-branch))
|
||||
(range (concat target "..")))
|
||||
(when (magit--insert-pushremote-log-p)
|
||||
(magit-insert-section (unpushed range t)
|
||||
(magit-insert-heading
|
||||
(format (propertize "Unpushed to %s."
|
||||
'font-lock-face 'magit-section-heading)
|
||||
(propertize target 'font-lock-face 'magit-branch-remote)))
|
||||
(magit--insert-log nil range magit-buffer-log-args)
|
||||
(magit-log-insert-child-count)))))
|
||||
(range (concat target ".."))
|
||||
((magit--insert-pushremote-log-p)))
|
||||
(magit-insert-section (unpushed range t)
|
||||
(magit-insert-heading
|
||||
(format (propertize "Unpushed to %s."
|
||||
'font-lock-face 'magit-section-heading)
|
||||
(propertize target 'font-lock-face 'magit-branch-remote)))
|
||||
(magit--insert-log nil range magit-buffer-log-args)
|
||||
(magit-log-insert-child-count))))
|
||||
|
||||
(defun magit--insert-pushremote-log-p ()
|
||||
(magit--with-refresh-cache
|
||||
@@ -1980,7 +2035,7 @@ not shared with any local commit) with \"+\", and all others with
|
||||
\"-\"."
|
||||
(when (magit-git-success "rev-parse" "@{upstream}")
|
||||
(magit-insert-section (unpulled "..@{upstream}")
|
||||
(magit-insert-heading "Unpulled commits:")
|
||||
(magit-insert-heading t "Unpulled commits")
|
||||
(magit-git-wash (apply-partially #'magit-log-wash-log 'cherry)
|
||||
"cherry" "-v" (magit-abbrev-arg)
|
||||
(magit-get-current-branch) "@{upstream}"))))
|
||||
@@ -1993,7 +2048,7 @@ a patch-id not shared with any upstream commit) with \"+\", and
|
||||
all others with \"-\"."
|
||||
(when (magit-git-success "rev-parse" "@{upstream}")
|
||||
(magit-insert-section (unpushed "@{upstream}..")
|
||||
(magit-insert-heading "Unpushed commits:")
|
||||
(magit-insert-heading t "Unpushed commits")
|
||||
(magit-git-wash (apply-partially #'magit-log-wash-log 'cherry)
|
||||
"cherry" "-v" (magit-abbrev-arg) "@{upstream}"))))
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-margin.el --- Margins in Magit buffers -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -62,14 +62,16 @@ does not carry to other options."
|
||||
"Change what information is displayed in the margin."
|
||||
:info-manual "(magit) Log Margin"
|
||||
["Margin"
|
||||
("L" "Toggle visibility" magit-toggle-margin :transient t)
|
||||
("l" "Cycle style" magit-cycle-margin-style :transient t)
|
||||
("d" "Toggle details" magit-toggle-margin-details)
|
||||
("v" "Change verbosity" magit-refs-set-show-commit-count
|
||||
:if-derived magit-refs-mode)])
|
||||
(magit-toggle-margin)
|
||||
(magit-cycle-margin-style)
|
||||
(magit-toggle-margin-details)
|
||||
(magit-refs-set-show-commit-count)])
|
||||
|
||||
(defun magit-toggle-margin ()
|
||||
(transient-define-suffix magit-toggle-margin ()
|
||||
"Show or hide the Magit margin."
|
||||
:description "Toggle visibility"
|
||||
:key "L"
|
||||
:transient t
|
||||
(interactive)
|
||||
(unless (magit-margin-option)
|
||||
(user-error "Magit margin isn't supported in this buffer"))
|
||||
@@ -79,8 +81,11 @@ does not carry to other options."
|
||||
(defvar magit-margin-default-time-format nil
|
||||
"See https://github.com/magit/magit/pull/4605.")
|
||||
|
||||
(defun magit-cycle-margin-style ()
|
||||
(transient-define-suffix magit-cycle-margin-style ()
|
||||
"Cycle style used for the Magit margin."
|
||||
:description "Cycle style"
|
||||
:key "l"
|
||||
:transient t
|
||||
(interactive)
|
||||
(unless (magit-margin-option)
|
||||
(user-error "Magit margin isn't supported in this buffer"))
|
||||
@@ -95,8 +100,11 @@ does not carry to other options."
|
||||
(_ 'age)))
|
||||
(magit-set-buffer-margin nil t))
|
||||
|
||||
(defun magit-toggle-margin-details ()
|
||||
(transient-define-suffix magit-toggle-margin-details ()
|
||||
"Show or hide details in the Magit margin."
|
||||
:description "Toggle details"
|
||||
:key "d"
|
||||
:transient t
|
||||
(interactive)
|
||||
(unless (magit-margin-option)
|
||||
(user-error "Magit margin isn't supported in this buffer"))
|
||||
@@ -118,7 +126,8 @@ does not carry to other options."
|
||||
('magit-refs-mode 'magit-refs-margin)
|
||||
('magit-stashes-mode 'magit-stashes-margin)
|
||||
('magit-status-mode 'magit-status-margin)
|
||||
('forge-notifications-mode 'magit-status-margin)))
|
||||
('forge-notifications-mode 'magit-status-margin)
|
||||
('forge-topics-mode 'magit-status-margin)))
|
||||
|
||||
(defun magit-set-buffer-margin (&optional reset refresh)
|
||||
(when-let ((option (magit-margin-option)))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-merge.el --- Merge functionality -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
(5 "-b" "Ignore changes in amount of whitespace" "-Xignore-space-change")
|
||||
(5 "-w" "Ignore whitespace when comparing lines" "-Xignore-all-space")
|
||||
(5 magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=")
|
||||
(5 magit:--gpg-sign)]
|
||||
(magit:--gpg-sign)
|
||||
(magit:--signoff)]
|
||||
["Actions"
|
||||
:if-not magit-merge-in-progress-p
|
||||
[("m" "Merge" magit-merge-plain)
|
||||
@@ -291,10 +292,6 @@ then also remove the respective remote branch."
|
||||
|
||||
;;; Sections
|
||||
|
||||
(defvar-keymap magit-unmerged-section-map
|
||||
:doc "Keymap for `unmerged' sections."
|
||||
:parent magit-log-section-map)
|
||||
|
||||
(defun magit-insert-merge-log ()
|
||||
"Insert section for the on-going merge.
|
||||
Display the heads that are being merged.
|
||||
@@ -306,7 +303,7 @@ If no merge is in progress, do nothing."
|
||||
(range (magit--merge-range (car heads))))
|
||||
(magit-insert-section (unmerged range)
|
||||
(magit-insert-heading
|
||||
(format "Merging %s:" (mapconcat #'identity heads ", ")))
|
||||
(format "Merging %s:" (string-join heads ", ")))
|
||||
(magit--insert-log nil
|
||||
range
|
||||
(let ((args magit-buffer-log-args))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-mode.el --- Create and refresh Magit buffers -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -31,11 +31,21 @@
|
||||
(require 'magit-base)
|
||||
(require 'magit-git)
|
||||
|
||||
(require 'benchmark)
|
||||
(require 'browse-url)
|
||||
(require 'format-spec)
|
||||
(require 'help-mode)
|
||||
|
||||
(require 'transient)
|
||||
|
||||
(defvar bookmark-make-record-function)
|
||||
|
||||
(eval-when-compile (require 'elp))
|
||||
(declare-function elp-reset-all "elp" ())
|
||||
(declare-function elp-instrument-package "elp" (prefix))
|
||||
(declare-function elp-results "elp" ())
|
||||
(declare-function elp-restore-all "elp" ())
|
||||
|
||||
(defvar magit--wip-inhibit-autosave)
|
||||
(defvar magit-wip-after-save-local-mode)
|
||||
(declare-function magit-wip-get-ref "magit-wip" ())
|
||||
@@ -44,17 +54,17 @@
|
||||
;;; Options
|
||||
|
||||
(defcustom magit-mode-hook
|
||||
'(magit-load-config-extensions)
|
||||
(list #'magit-load-config-extensions)
|
||||
"Hook run when entering a mode derived from Magit mode."
|
||||
:package-version '(magit . "3.0.0")
|
||||
:group 'magit-modes
|
||||
:type 'hook
|
||||
:options '(magit-load-config-extensions
|
||||
bug-reference-mode))
|
||||
:options (list #'magit-load-config-extensions
|
||||
#'bug-reference-mode))
|
||||
|
||||
(defcustom magit-setup-buffer-hook
|
||||
'(magit-maybe-save-repository-buffers
|
||||
magit-set-buffer-margin)
|
||||
(list #'magit-maybe-save-repository-buffers
|
||||
'magit-set-buffer-margin) ; from magit-margin.el
|
||||
"Hook run by `magit-setup-buffer'.
|
||||
|
||||
This is run right after displaying the buffer and right before
|
||||
@@ -65,10 +75,11 @@ should be used instead of this one."
|
||||
:package-version '(magit . "2.3.0")
|
||||
:group 'magit-modes
|
||||
:type 'hook
|
||||
:options '(magit-maybe-save-repository-buffers
|
||||
magit-set-buffer-margin))
|
||||
:options (list #'magit-maybe-save-repository-buffers
|
||||
'magit-set-buffer-margin))
|
||||
|
||||
(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers)
|
||||
(defcustom magit-pre-refresh-hook
|
||||
(list #'magit-maybe-save-repository-buffers)
|
||||
"Hook run before refreshing in `magit-refresh'.
|
||||
|
||||
This hook, or `magit-post-refresh-hook', should be used
|
||||
@@ -80,9 +91,10 @@ inside your function."
|
||||
:package-version '(magit . "2.4.0")
|
||||
:group 'magit-refresh
|
||||
:type 'hook
|
||||
:options '(magit-maybe-save-repository-buffers))
|
||||
:options (list #'magit-maybe-save-repository-buffers))
|
||||
|
||||
(defcustom magit-post-refresh-hook
|
||||
;; Do not function-quote to avoid circular dependencies.
|
||||
'(magit-auto-revert-buffers
|
||||
magit-run-post-commit-hook
|
||||
magit-run-post-stage-hook
|
||||
@@ -111,36 +123,37 @@ All Magit buffers (buffers whose major-modes derive from
|
||||
which in turn uses the function specified here."
|
||||
:package-version '(magit . "2.3.0")
|
||||
:group 'magit-buffers
|
||||
:type '(radio (function-item magit-display-buffer-traditional)
|
||||
(function-item magit-display-buffer-same-window-except-diff-v1)
|
||||
(function-item magit-display-buffer-fullframe-status-v1)
|
||||
(function-item magit-display-buffer-fullframe-status-topleft-v1)
|
||||
(function-item magit-display-buffer-fullcolumn-most-v1)
|
||||
(function-item display-buffer)
|
||||
:type `(radio (function-item ,#'magit-display-buffer-traditional)
|
||||
(function-item ,#'magit-display-buffer-same-window-except-diff-v1)
|
||||
(function-item ,#'magit-display-buffer-fullframe-status-v1)
|
||||
(function-item ,#'magit-display-buffer-fullframe-status-topleft-v1)
|
||||
(function-item ,#'magit-display-buffer-fullcolumn-most-v1)
|
||||
(function-item ,#'display-buffer)
|
||||
(function :tag "Function")))
|
||||
|
||||
(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration)
|
||||
(defcustom magit-pre-display-buffer-hook
|
||||
(list #'magit-save-window-configuration)
|
||||
"Hook run by `magit-display-buffer' before displaying the buffer."
|
||||
:package-version '(magit . "2.3.0")
|
||||
:group 'magit-buffers
|
||||
:type 'hook
|
||||
:get #'magit-hook-custom-get
|
||||
:options '(magit-save-window-configuration))
|
||||
:options (list #'magit-save-window-configuration))
|
||||
|
||||
(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated)
|
||||
(defcustom magit-post-display-buffer-hook (list #'magit-maybe-set-dedicated)
|
||||
"Hook run by `magit-display-buffer' after displaying the buffer."
|
||||
:package-version '(magit . "2.3.0")
|
||||
:group 'magit-buffers
|
||||
:type 'hook
|
||||
:get #'magit-hook-custom-get
|
||||
:options '(magit-maybe-set-dedicated))
|
||||
:options (list #'magit-maybe-set-dedicated))
|
||||
|
||||
(defcustom magit-generate-buffer-name-function
|
||||
#'magit-generate-buffer-name-default-function
|
||||
"The function used to generate the name for a Magit buffer."
|
||||
:package-version '(magit . "2.3.0")
|
||||
:group 'magit-buffers
|
||||
:type '(radio (function-item magit-generate-buffer-name-default-function)
|
||||
:type `(radio (function-item ,#'magit-generate-buffer-name-default-function)
|
||||
(function :tag "Function")))
|
||||
|
||||
(defcustom magit-buffer-name-format "%x%M%v: %t%x"
|
||||
@@ -189,9 +202,9 @@ support additional %-sequences."
|
||||
"The function used to bury or kill the current Magit buffer."
|
||||
:package-version '(magit . "3.2.0")
|
||||
:group 'magit-buffers
|
||||
:type '(radio (function-item quit-window)
|
||||
(function-item magit-mode-quit-window)
|
||||
(function-item magit-restore-window-configuration)
|
||||
:type `(radio (function-item ,#'quit-window)
|
||||
(function-item ,#'magit-mode-quit-window)
|
||||
(function-item ,#'magit-restore-window-configuration)
|
||||
(function :tag "Function")))
|
||||
|
||||
(defcustom magit-prefix-use-buffer-arguments 'selected
|
||||
@@ -259,7 +272,8 @@ and Buffer Variables'."
|
||||
(const :tag "use args from buffer if it is current" current)
|
||||
(const :tag "never use args from buffer" never)))
|
||||
|
||||
(defcustom magit-region-highlight-hook '(magit-diff-update-hunk-region)
|
||||
(defcustom magit-region-highlight-hook
|
||||
'(magit-diff-update-hunk-region) ; from magit-diff.el
|
||||
"Functions used to highlight the region.
|
||||
|
||||
Each function is run with the current section as only argument
|
||||
@@ -271,11 +285,22 @@ then fall back to regular region highlighting."
|
||||
:options '(magit-diff-update-hunk-region))
|
||||
|
||||
(defcustom magit-create-buffer-hook nil
|
||||
"Normal hook run after creating a new `magit-mode' buffer."
|
||||
"Normal hook run while creating a new `magit-mode' buffer.
|
||||
Runs before the buffer is populated with sections. Also see
|
||||
`magit-post-create-buffer-hook'."
|
||||
:package-version '(magit . "2.90.0")
|
||||
:group 'magit-refresh
|
||||
:type 'hook)
|
||||
|
||||
(defcustom magit-post-create-buffer-hook nil
|
||||
"Normal hook run after creating a new `magit-mode' buffer.
|
||||
Runs after the buffer is populated with sections for the first
|
||||
time. Also see `magit-create-buffer-hook' (which runs earlier)
|
||||
and `magit-refresh-buffer-hook' (which runs on every refresh)."
|
||||
:package-version '(magit . "4.0.0")
|
||||
:group 'magit-refresh
|
||||
:type 'hook)
|
||||
|
||||
(defcustom magit-refresh-buffer-hook nil
|
||||
"Normal hook for `magit-refresh-buffer' to run after refreshing."
|
||||
:package-version '(magit . "2.1.0")
|
||||
@@ -394,15 +419,17 @@ recommended value."
|
||||
"!" 'magit-run
|
||||
">" 'magit-sparse-checkout
|
||||
"C-c C-c" 'magit-dispatch
|
||||
"C-c C-r" 'magit-next-reference
|
||||
"C-c C-e" 'magit-edit-thing
|
||||
"C-c C-o" 'magit-browse-thing
|
||||
"C-c C-w" 'magit-copy-thing
|
||||
"C-w" 'magit-copy-section-value
|
||||
"M-w" 'magit-copy-buffer-revision
|
||||
"<remap> <previous-line>" 'magit-previous-line
|
||||
"<remap> <next-line>" 'magit-next-line
|
||||
"<remap> <evil-previous-line>" 'evil-previous-visual-line
|
||||
"<remap> <evil-next-line>" 'evil-next-visual-line)
|
||||
"<remap> <back-to-indentation>" 'magit-back-to-indentation
|
||||
"<remap> <previous-line>" 'magit-previous-line
|
||||
"<remap> <next-line>" 'magit-next-line
|
||||
"<remap> <evil-previous-line>" 'evil-previous-visual-line
|
||||
"<remap> <evil-next-line>" 'evil-next-visual-line)
|
||||
|
||||
(defun magit-delete-thing ()
|
||||
"This is a placeholder command, which signals an error if called.
|
||||
@@ -410,6 +437,8 @@ Where applicable, other keymaps remap this command to another,
|
||||
which actually deletes the thing at point."
|
||||
(interactive)
|
||||
(user-error "There is no thing at point that could be deleted"))
|
||||
;; Starting with Emacs 28.1 we could use (declare (completion ignore)).
|
||||
(put 'magit-delete-thing 'completion-predicate #'ignore)
|
||||
|
||||
(defun magit-visit-thing ()
|
||||
"This is a placeholder command, which may signal an error if called.
|
||||
@@ -418,7 +447,10 @@ which actually visits the thing at point."
|
||||
(interactive)
|
||||
(if (eq transient-current-command 'magit-dispatch)
|
||||
(call-interactively (key-binding (this-command-keys)))
|
||||
(user-error "There is no thing at point that could be visited")))
|
||||
(if-let ((url (thing-at-point 'url t)))
|
||||
(browse-url url)
|
||||
(user-error "There is no thing at point that could be visited"))))
|
||||
(put 'magit-visit-thing 'completion-predicate #'ignore)
|
||||
|
||||
(defun magit-edit-thing ()
|
||||
"This is a placeholder command, which may signal an error if called.
|
||||
@@ -429,13 +461,17 @@ buffer."
|
||||
(if (eq transient-current-command 'magit-dispatch)
|
||||
(call-interactively (key-binding (this-command-keys)))
|
||||
(user-error "There is no thing at point that could be edited")))
|
||||
(put 'magit-edit-thing 'completion-predicate #'ignore)
|
||||
|
||||
(defun magit-browse-thing ()
|
||||
"This is a placeholder command, which signals an error if called.
|
||||
"This is a placeholder command, which may signal an error if called.
|
||||
Where applicable, other keymaps remap this command to another,
|
||||
which actually visits thing at point using `browse-url'."
|
||||
(interactive)
|
||||
(user-error "There is no thing at point that could be browsed"))
|
||||
(if-let ((url (thing-at-point 'url t)))
|
||||
(browse-url url)
|
||||
(user-error "There is no thing at point that could be browsed")))
|
||||
(put 'magit-browse-thing 'completion-predicate #'ignore)
|
||||
|
||||
(defun magit-copy-thing ()
|
||||
"This is a placeholder command, which signals an error if called.
|
||||
@@ -444,6 +480,7 @@ which actually copies some representation of the thing at point
|
||||
to the kill ring."
|
||||
(interactive)
|
||||
(user-error "There is no thing at point that we know how to copy"))
|
||||
(put 'magit-copy-thing 'completion-predicate #'ignore)
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-info ()
|
||||
@@ -457,7 +494,7 @@ to the kill ring."
|
||||
'bug-reference-push-button))
|
||||
|
||||
(easy-menu-define magit-mode-menu magit-mode-map
|
||||
"Magit menu"
|
||||
"Magit menu."
|
||||
;; Similar to `magit-dispatch' but exclude:
|
||||
;; - commands that are available from context menus:
|
||||
;; apply, reverse, discard, stage, unstage,
|
||||
@@ -528,8 +565,9 @@ to the kill ring."
|
||||
"Parent major mode from which Magit major modes inherit.
|
||||
|
||||
Magit is documented in info node `(magit)'."
|
||||
:interactive nil
|
||||
:group 'magit
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(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)
|
||||
@@ -538,6 +576,13 @@ Magit is documented in info node `(magit)'."
|
||||
(setq-local imenu-default-goto-function #'magit--imenu-goto-function)
|
||||
(setq-local isearch-filter-predicate #'magit-section--open-temporarily))
|
||||
|
||||
(defun magit-hack-dir-local-variables ()
|
||||
"Like `hack-dir-local-variables-non-file-buffer' but ignore some variables."
|
||||
(let ((ignored-local-variables
|
||||
`(show-trailing-whitespace
|
||||
,@ignored-local-variables)))
|
||||
(hack-dir-local-variables-non-file-buffer)))
|
||||
|
||||
;;; Local Variables
|
||||
|
||||
(defvar-local magit-buffer-arguments nil)
|
||||
@@ -579,9 +624,6 @@ The buffer's major-mode should derive from `magit-section-mode'."
|
||||
(defvar-local magit-previous-section nil)
|
||||
(put 'magit-previous-section 'permanent-local t)
|
||||
|
||||
(defvar-local magit--imenu-group-types nil)
|
||||
(defvar-local magit--imenu-item-types nil)
|
||||
|
||||
;;; Setup Buffer
|
||||
|
||||
(defmacro magit-setup-buffer (mode &optional locked &rest bindings)
|
||||
@@ -592,20 +634,25 @@ The buffer's major-mode should derive from `magit-section-mode'."
|
||||
`(list ',var ,form))
|
||||
bindings))))
|
||||
|
||||
(defun magit-setup-buffer-internal (mode locked bindings)
|
||||
(defun magit-setup-buffer-internal ( mode locked bindings
|
||||
&optional buffer-or-name directory)
|
||||
(let* ((value (and locked
|
||||
(with-temp-buffer
|
||||
(pcase-dolist (`(,var ,val) bindings)
|
||||
(set (make-local-variable var) val))
|
||||
(let ((major-mode mode))
|
||||
(magit-buffer-value)))))
|
||||
(buffer (magit-get-mode-buffer mode value))
|
||||
(buffer (if buffer-or-name
|
||||
(get-buffer-create buffer-or-name)
|
||||
(magit-get-mode-buffer mode value)))
|
||||
(section (and buffer (magit-current-section)))
|
||||
(created (not buffer)))
|
||||
(unless buffer
|
||||
(setq buffer (magit-generate-new-buffer mode value)))
|
||||
(with-current-buffer buffer
|
||||
(setq magit-previous-section section)
|
||||
(when directory
|
||||
(setq default-directory directory))
|
||||
(funcall mode)
|
||||
(magit-xref-setup #'magit-setup-buffer-internal bindings)
|
||||
(pcase-dolist (`(,var ,val) bindings)
|
||||
@@ -615,7 +662,9 @@ 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)
|
||||
(when created
|
||||
(run-hooks 'magit-post-create-buffer-hook)))
|
||||
buffer))
|
||||
|
||||
;;; Display Buffer
|
||||
@@ -786,10 +835,10 @@ into thinking a buffer belongs to a repo that it doesn't.")
|
||||
|
||||
(defun magit-mode-get-buffers ()
|
||||
(let ((topdir (magit-toplevel)))
|
||||
(--filter (with-current-buffer it
|
||||
(and (derived-mode-p 'magit-mode)
|
||||
(equal magit--default-directory topdir)))
|
||||
(buffer-list))))
|
||||
(seq-filter (##with-current-buffer %
|
||||
(and (derived-mode-p 'magit-mode)
|
||||
(equal magit--default-directory topdir)))
|
||||
(buffer-list))))
|
||||
|
||||
(defvar-local magit-buffer-locked-p nil)
|
||||
(put 'magit-buffer-locked-p 'permanent-local t)
|
||||
@@ -841,7 +890,7 @@ If a frame, then only consider buffers on that frame."
|
||||
(setq magit-buffer-locked-p (and value t))
|
||||
(magit-restore-section-visibility-cache mode))
|
||||
(when magit-uniquify-buffer-names
|
||||
(add-to-list 'uniquify-list-buffers-directory-modes mode)
|
||||
(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
|
||||
@@ -859,7 +908,7 @@ The returned name is based on `magit-buffer-name-format' and
|
||||
takes `magit-uniquify-buffer-names' and VALUE, if non-nil, into
|
||||
account."
|
||||
(let ((m (substring (symbol-name mode) 0 -5))
|
||||
(v (and value (format "%s" (if (listp value) value (list value)))))
|
||||
(v (and value (format "%s" (ensure-list value))))
|
||||
(n (if magit-uniquify-buffer-names
|
||||
(file-name-nondirectory
|
||||
(directory-file-name default-directory))
|
||||
@@ -935,14 +984,14 @@ current buffer is the last remaining Magit buffer that was
|
||||
ever displayed in the selected window, then delete that
|
||||
window."
|
||||
(if (or (one-window-p)
|
||||
(--first (let ((buffer (car it)))
|
||||
(and (not (eq buffer (current-buffer)))
|
||||
(buffer-live-p buffer)
|
||||
(or (not (window-parameter nil 'magit-dedicated))
|
||||
(with-current-buffer buffer
|
||||
(derived-mode-p 'magit-mode
|
||||
'magit-process-mode)))))
|
||||
(window-prev-buffers)))
|
||||
(seq-find (pcase-lambda (`(,buffer))
|
||||
(and (not (eq buffer (current-buffer)))
|
||||
(buffer-live-p buffer)
|
||||
(or (not (window-parameter nil 'magit-dedicated))
|
||||
(with-current-buffer buffer
|
||||
(derived-mode-p 'magit-mode
|
||||
'magit-process-mode)))))
|
||||
(window-prev-buffers)))
|
||||
(quit-window kill-buffer)
|
||||
(let ((window (selected-window)))
|
||||
(quit-window kill-buffer)
|
||||
@@ -983,7 +1032,7 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
|
||||
(let* ((c (caar magit--refresh-cache))
|
||||
(a (+ c (cdar magit--refresh-cache))))
|
||||
(message "Refreshing magit...done (%.3fs, cached %s/%s (%.0f%%))"
|
||||
(float-time (time-subtract (current-time) start))
|
||||
(float-time (time-since start))
|
||||
c a (* (/ c (* a 1.0)) 100)))))
|
||||
(run-hooks 'magit-unwind-refresh-hook))))
|
||||
|
||||
@@ -1005,6 +1054,7 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
|
||||
|
||||
(defun magit-refresh-buffer (&rest _ignore)
|
||||
"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))))
|
||||
@@ -1013,7 +1063,7 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
|
||||
(when magit-refresh-verbose
|
||||
(message "Refreshing buffer `%s'..." (buffer-name)))
|
||||
(let* ((buffer (current-buffer))
|
||||
(windows (cl-mapcan
|
||||
(windows (mapcan
|
||||
(lambda (window)
|
||||
(with-selected-window window
|
||||
(with-current-buffer buffer
|
||||
@@ -1049,8 +1099,37 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
|
||||
(set-buffer-modified-p nil))
|
||||
(when magit-refresh-verbose
|
||||
(message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name)
|
||||
(float-time (time-subtract (current-time)
|
||||
magit-refresh-start-time)))))))
|
||||
(float-time (time-since magit-refresh-start-time)))))))
|
||||
|
||||
(defun magit-profile-refresh-buffer ()
|
||||
"Profile refreshing the current Magit buffer."
|
||||
(interactive)
|
||||
(require (quote elp))
|
||||
(elp-reset-all)
|
||||
(message "Profiling Magit and Forge...")
|
||||
(elp-instrument-package "magit-")
|
||||
(elp-instrument-package "forge-")
|
||||
(magit-refresh-buffer)
|
||||
(message "Profiling Magit and Forge...done")
|
||||
(elp-results)
|
||||
(elp-reset-all))
|
||||
|
||||
(defun magit-toggle-profiling ()
|
||||
"Start profiling Magit, or if in progress, stop and display the results."
|
||||
(interactive)
|
||||
(require (quote elp))
|
||||
(cond ((catch 'in-progress
|
||||
(mapatoms (lambda (symbol)
|
||||
(and (get symbol elp-timer-info-property)
|
||||
(throw 'in-progress t)))))
|
||||
(message "Stop profiling and display results...")
|
||||
(elp-results)
|
||||
(elp-restore-all))
|
||||
(t
|
||||
(message "Start profiling Magit and Forge...")
|
||||
(elp-reset-all)
|
||||
(elp-instrument-package "magit-")
|
||||
(elp-instrument-package "forge-"))))
|
||||
|
||||
;;; Save File-Visiting Buffers
|
||||
|
||||
@@ -1083,12 +1162,11 @@ Note that refreshing a Magit buffer is done by re-creating its
|
||||
contents from scratch, which can be slow in large repositories.
|
||||
If you are not satisfied with Magit's performance, then you
|
||||
should obviously not add this function to that hook."
|
||||
(when (and (not magit--disable-save-buffers)
|
||||
(magit-inside-worktree-p t))
|
||||
(when-let ((buffer (ignore-errors
|
||||
(magit-get-mode-buffer 'magit-status-mode))))
|
||||
(add-to-list 'magit-after-save-refresh-buffers buffer)
|
||||
(add-hook 'post-command-hook #'magit-after-save-refresh-buffers))))
|
||||
(when-let (((and (not magit--disable-save-buffers)
|
||||
(magit-inside-worktree-p t)))
|
||||
(buf (ignore-errors (magit-get-mode-buffer 'magit-status-mode))))
|
||||
(cl-pushnew buf magit-after-save-refresh-buffers)
|
||||
(add-hook 'post-command-hook #'magit-after-save-refresh-buffers)))
|
||||
|
||||
(defun magit-maybe-save-repository-buffers ()
|
||||
"Maybe save file-visiting buffers belonging to the current repository.
|
||||
@@ -1106,10 +1184,6 @@ if you so desire."
|
||||
(not (equal msg (current-message))))
|
||||
(message "%s" msg)))))
|
||||
|
||||
(add-hook 'magit-pre-refresh-hook #'magit-maybe-save-repository-buffers)
|
||||
(add-hook 'magit-pre-call-git-hook #'magit-maybe-save-repository-buffers)
|
||||
(add-hook 'magit-pre-start-git-hook #'magit-maybe-save-repository-buffers)
|
||||
|
||||
(defvar-local magit-inhibit-refresh-save nil)
|
||||
|
||||
(defun magit-save-repository-buffers (&optional arg)
|
||||
@@ -1256,6 +1330,7 @@ Later, when the buffer is buried, it may be restored by
|
||||
'help-echo (purecopy "mouse-2, RET: go back to next history entry"))
|
||||
|
||||
(defvar magit-xref-modes
|
||||
;; Do not function-quote to avoid circular dependencies.
|
||||
'(magit-log-mode
|
||||
magit-reflog-mode
|
||||
magit-diff-mode
|
||||
@@ -1338,11 +1413,16 @@ Unless specified, REPOSITORY is the current buffer's repository."
|
||||
(defun magit-repository-local-delete (key &optional repository)
|
||||
"Delete the repository-local value for KEY.
|
||||
|
||||
Unless specified, REPOSITORY is the current buffer's repository."
|
||||
(when-let ((cache (assoc (or repository
|
||||
(magit-repository-local-repository))
|
||||
magit-repository-local-cache)))
|
||||
(setf cache (compat-call assoc-delete-all key cache))))
|
||||
Unless specified, REPOSITORY is the current buffer's repository.
|
||||
If REPOSITORY is `all', then delete the value for KEY for all
|
||||
repositories."
|
||||
(if (eq repository 'all)
|
||||
(dolist (cache magit-repository-local-cache)
|
||||
(setf cache (compat-call assoc-delete-all key cache)))
|
||||
(when-let ((cache (assoc (or repository
|
||||
(magit-repository-local-repository))
|
||||
magit-repository-local-cache)))
|
||||
(setf cache (compat-call assoc-delete-all key cache)))))
|
||||
|
||||
(defmacro magit--with-repository-local-cache (key &rest body)
|
||||
(declare (indent 1) (debug (form body)))
|
||||
@@ -1369,9 +1449,9 @@ Unless specified, REPOSITORY is the current buffer's repository."
|
||||
"Zap caches for the current repository.
|
||||
|
||||
Remove the repository's entry from `magit-repository-local-cache',
|
||||
remove the host's entry from `magit--host-git-version-cache', set
|
||||
`magit-section-visibility-cache' to nil for all Magit buffers of
|
||||
the repository and set `magit--libgit-available-p' to `unknown'.
|
||||
remove the host's entry from `magit--host-git-version-cache', and
|
||||
set `magit-section-visibility-cache' to nil for all Magit buffers
|
||||
of the repository.
|
||||
|
||||
With a prefix argument or if optional ALL is non-nil, discard the
|
||||
mentioned caches completely."
|
||||
@@ -1395,155 +1475,7 @@ mentioned caches completely."
|
||||
:key #'car :test #'equal)))
|
||||
(dolist (buffer (magit-mode-get-buffers))
|
||||
(with-current-buffer buffer
|
||||
(setq magit-section-visibility-cache nil)))))
|
||||
(setq magit--libgit-available-p 'unknown))
|
||||
|
||||
;;; Imenu Support
|
||||
|
||||
(defun magit--imenu-create-index ()
|
||||
;; If `which-function-mode' is active, then the create-index
|
||||
;; function is called at the time the major-mode is being enabled.
|
||||
;; Modes that derive from `magit-mode' have not populated the buffer
|
||||
;; at that time yet, so we have to abort.
|
||||
(and magit-root-section
|
||||
(or magit--imenu-group-types
|
||||
magit--imenu-item-types)
|
||||
(let ((index
|
||||
(cl-mapcan
|
||||
(lambda (section)
|
||||
(cond
|
||||
(magit--imenu-group-types
|
||||
(and (if (eq (car-safe magit--imenu-group-types) 'not)
|
||||
(not (magit-section-match
|
||||
(cdr magit--imenu-group-types)
|
||||
section))
|
||||
(magit-section-match magit--imenu-group-types section))
|
||||
(and-let* ((children (oref section children)))
|
||||
`((,(magit--imenu-index-name section)
|
||||
,@(mapcar (lambda (s)
|
||||
(cons (magit--imenu-index-name s)
|
||||
(oref s start)))
|
||||
children))))))
|
||||
(magit--imenu-item-types
|
||||
(and (magit-section-match magit--imenu-item-types section)
|
||||
`((,(magit--imenu-index-name section)
|
||||
. ,(oref section start)))))))
|
||||
(oref magit-root-section children))))
|
||||
(if (and magit--imenu-group-types (symbolp magit--imenu-group-types))
|
||||
(cdar index)
|
||||
index))))
|
||||
|
||||
(defun magit--imenu-index-name (section)
|
||||
(let ((heading (buffer-substring-no-properties
|
||||
(oref section start)
|
||||
(1- (or (oref section content)
|
||||
(oref section end))))))
|
||||
(save-match-data
|
||||
(cond
|
||||
((and (magit-section-match [commit logbuf] section)
|
||||
(string-match "[^ ]+\\([ *|]*\\).+" heading))
|
||||
(replace-match " " t t heading 1))
|
||||
((magit-section-match
|
||||
'([branch local branchbuf] [tag tags branchbuf]) section)
|
||||
(oref section value))
|
||||
((magit-section-match [branch remote branchbuf] section)
|
||||
(concat (oref (oref section parent) value) "/"
|
||||
(oref section value)))
|
||||
((string-match " ([0-9]+)\\'" heading)
|
||||
(substring heading 0 (match-beginning 0)))
|
||||
(t heading)))))
|
||||
|
||||
(defun magit--imenu-goto-function (_name position &rest _rest)
|
||||
"Go to the section at POSITION.
|
||||
Make sure it is visible, by showing its ancestors where
|
||||
necessary. For use as `imenu-default-goto-function' in
|
||||
`magit-mode' buffers."
|
||||
(goto-char position)
|
||||
(let ((section (magit-current-section)))
|
||||
(while (setq section (oref section parent))
|
||||
(when (oref section hidden)
|
||||
(magit-section-show section)))))
|
||||
|
||||
;;; Bookmark support
|
||||
|
||||
(declare-function bookmark-get-filename "bookmark" (bookmark-name-or-record))
|
||||
(declare-function bookmark-make-record-default "bookmark"
|
||||
(&optional no-file no-context posn))
|
||||
(declare-function bookmark-prop-get "bookmark" (bookmark-name-or-record prop))
|
||||
(declare-function bookmark-prop-set "bookmark" (bookmark-name-or-record prop val))
|
||||
|
||||
(defun magit--make-bookmark ()
|
||||
"Create a bookmark for the current Magit buffer.
|
||||
Input values are the major-mode's `magit-bookmark-name' method,
|
||||
and the buffer-local values of the variables referenced in its
|
||||
`magit-bookmark-variables' property."
|
||||
(require 'bookmark)
|
||||
(if (plist-member (symbol-plist major-mode) 'magit-bookmark-variables)
|
||||
;; `bookmark-make-record-default's return value does not match
|
||||
;; (NAME . ALIST), even though it is used as the default value
|
||||
;; of `bookmark-make-record-function', which states that such
|
||||
;; functions must do that. See #4356.
|
||||
(let ((bookmark (cons nil (bookmark-make-record-default 'no-file))))
|
||||
(bookmark-prop-set bookmark 'handler #'magit--handle-bookmark)
|
||||
(bookmark-prop-set bookmark 'mode major-mode)
|
||||
(bookmark-prop-set bookmark 'filename (magit-toplevel))
|
||||
(bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name)))
|
||||
(dolist (var (get major-mode 'magit-bookmark-variables))
|
||||
(bookmark-prop-set bookmark var (symbol-value var)))
|
||||
(bookmark-prop-set
|
||||
bookmark 'magit-hidden-sections
|
||||
(--keep (and (oref it hidden)
|
||||
(cons (oref it type)
|
||||
(if (derived-mode-p 'magit-stash-mode)
|
||||
(string-replace magit-buffer-revision
|
||||
magit-buffer-revision-hash
|
||||
(oref it value))
|
||||
(oref it value))))
|
||||
(oref magit-root-section children)))
|
||||
bookmark)
|
||||
(user-error "Bookmarking is not implemented for %s buffers" major-mode)))
|
||||
|
||||
(defun magit--handle-bookmark (bookmark)
|
||||
"Open a bookmark created by `magit--make-bookmark'.
|
||||
Call the `magit-*-setup-buffer' function of the the major-mode
|
||||
with the variables' values as arguments, which were recorded by
|
||||
`magit--make-bookmark'. Ignore `magit-display-buffer-function'."
|
||||
(let ((buffer (let ((default-directory (bookmark-get-filename bookmark))
|
||||
(mode (bookmark-prop-get bookmark 'mode))
|
||||
(magit-display-buffer-function #'identity)
|
||||
(magit-display-buffer-noselect t))
|
||||
(apply (intern (format "%s-setup-buffer"
|
||||
(substring (symbol-name mode) 0 -5)))
|
||||
(--map (bookmark-prop-get bookmark it)
|
||||
(get mode 'magit-bookmark-variables))))))
|
||||
(set-buffer buffer) ; That is the interface we have to adhere to.
|
||||
(when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections)))
|
||||
(with-current-buffer buffer
|
||||
(dolist (child (oref magit-root-section children))
|
||||
(if (member (cons (oref child type)
|
||||
(oref child value))
|
||||
hidden)
|
||||
(magit-section-hide child)
|
||||
(magit-section-show child)))))
|
||||
;; Compatibility with `bookmark+' package. See #4356.
|
||||
(when (bound-and-true-p bmkp-jump-display-function)
|
||||
(funcall bmkp-jump-display-function (current-buffer)))
|
||||
nil))
|
||||
|
||||
(put 'magit--handle-bookmark 'bookmark-handler-type "Magit")
|
||||
|
||||
(cl-defgeneric magit-bookmark-name ()
|
||||
"Return name for bookmark to current buffer."
|
||||
(format "%s%s"
|
||||
(substring (symbol-name major-mode) 0 -5)
|
||||
(if-let ((vars (get major-mode 'magit-bookmark-variables)))
|
||||
(cl-mapcan (lambda (var)
|
||||
(let ((val (symbol-value var)))
|
||||
(if (and val (atom val))
|
||||
(list val)
|
||||
val)))
|
||||
vars)
|
||||
"")))
|
||||
(setq magit-section-visibility-cache nil))))))
|
||||
|
||||
;;; Utilities
|
||||
|
||||
@@ -1557,14 +1489,33 @@ The additional output can be found in the *Messages* buffer."
|
||||
(if magit-refresh-verbose "Enabled" "Disabled")))
|
||||
|
||||
(defun magit-run-hook-with-benchmark (hook)
|
||||
(when hook
|
||||
(if magit-refresh-verbose
|
||||
(let ((start (current-time)))
|
||||
(message "Running %s..." hook)
|
||||
(run-hooks hook)
|
||||
(message "Running %s...done (%.3fs)" hook
|
||||
(float-time (time-subtract (current-time) start))))
|
||||
(run-hooks hook))))
|
||||
(cond
|
||||
((not hook))
|
||||
(magit-refresh-verbose
|
||||
(message "Running %s..." hook)
|
||||
(message "Running %s...done (%.3fs)" hook
|
||||
(benchmark-elapse
|
||||
(run-hook-wrapped
|
||||
hook
|
||||
(lambda (fn)
|
||||
(message " %-50s %f" fn (benchmark-elapse (funcall fn))))))))
|
||||
((run-hooks hook))))
|
||||
|
||||
(defun magit-file-region-line-numbers ()
|
||||
"Return the bounds of the region as line numbers.
|
||||
The returned value has the form (BEGINNING-LINE END-LINE). If
|
||||
the region end at the beginning of a line, do not include that
|
||||
line. Avoid including the line after the end of the file."
|
||||
(and (or magit-buffer-file-name buffer-file-name)
|
||||
(region-active-p)
|
||||
(not (= (region-beginning) (region-end) (1+ (buffer-size))))
|
||||
(let ((beg (region-beginning))
|
||||
(end (min (region-end) (buffer-size))))
|
||||
(list (line-number-at-pos beg t)
|
||||
(line-number-at-pos (if (= (magit--bol-position end) end)
|
||||
(max beg (1- end))
|
||||
end)
|
||||
t)))))
|
||||
|
||||
;;; _
|
||||
(provide 'magit-mode)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-notes.el --- Notes support -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -192,8 +192,8 @@ Also see `magit-notes-merge'."
|
||||
|
||||
(defun magit-notes-read-args (prompt)
|
||||
(list (magit-read-branch-or-commit prompt (magit-stash-at-point))
|
||||
(and-let* ((str (--first (string-match "^--ref=\\(.+\\)" it)
|
||||
(transient-args 'magit-notes))))
|
||||
(and-let* ((str (seq-find (##string-match "^--ref=\\(.+\\)" %)
|
||||
(transient-args 'magit-notes))))
|
||||
(match-string 1 str))))
|
||||
|
||||
;;; _
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-patch.el --- Creating and applying patches -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
(define-package "magit" "20231103.1516" "A Git porcelain inside Emacs."
|
||||
'((emacs "25.1")
|
||||
(compat "29.1.3.4")
|
||||
(dash "20221013")
|
||||
(git-commit "20230101")
|
||||
(magit-section "20230101")
|
||||
(define-package "magit" "20250221.105" "A Git porcelain inside Emacs"
|
||||
'((emacs "27.1")
|
||||
(compat "30.0.2.0")
|
||||
(llama "0.6.0")
|
||||
(magit-section "4.3.0")
|
||||
(seq "2.24")
|
||||
(transient "20230201")
|
||||
(with-editor "20230118"))
|
||||
:commit "2b02bfb0495bf738e006d82f3a233e8f511b90b8" :authors
|
||||
(transient "0.8.4")
|
||||
(with-editor "3.4.3"))
|
||||
:commit "9914feb4d5a2feab091076be554d80781594869d" :authors
|
||||
'(("Marius Vollmer" . "marius.vollmer@gmail.com")
|
||||
("Jonas Bernoulli" . "jonas@bernoul.li"))
|
||||
("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev"))
|
||||
:maintainers
|
||||
'(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")
|
||||
("Kyle Meyer" . "kyle@kyleam.com"))
|
||||
:maintainer
|
||||
'("Jonas Bernoulli" . "jonas@bernoul.li")
|
||||
'("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")
|
||||
:keywords
|
||||
'("git" "tools" "vc")
|
||||
:url "https://github.com/magit/magit")
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-process.el --- Process functionality -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -35,8 +35,10 @@
|
||||
(require 'magit-mode)
|
||||
|
||||
(require 'ansi-color)
|
||||
(require 'auth-source)
|
||||
(require 'with-editor)
|
||||
|
||||
(defvar messages-buffer-name)
|
||||
(defvar y-or-n-p-map)
|
||||
|
||||
;;; Options
|
||||
@@ -91,16 +93,6 @@ When this is nil, no sections are ever removed."
|
||||
:group 'magit-process
|
||||
:type '(choice (const :tag "Never remove old sections" nil) integer))
|
||||
|
||||
(defvar magit-process-extreme-logging nil
|
||||
"Whether `magit-process-file' logs to the *Messages* buffer.
|
||||
|
||||
Only intended for temporary use when you try to figure out how
|
||||
Magit uses Git behind the scene. Output that normally goes to
|
||||
the magit-process buffer continues to go there. Not all output
|
||||
goes to either of these two buffers.
|
||||
|
||||
Also see `magit-git-debug'.")
|
||||
|
||||
(defcustom magit-process-error-tooltip-max-lines 20
|
||||
"The number of lines for `magit-process-error-lines' to return.
|
||||
|
||||
@@ -114,21 +106,22 @@ displays the text of `magit-process-error-summary' instead."
|
||||
integer))
|
||||
|
||||
(defcustom magit-credential-cache-daemon-socket
|
||||
(--some (pcase-let ((`(,prog . ,args) (split-string it)))
|
||||
(if (and prog
|
||||
(seq-some (lambda (line)
|
||||
(pcase-let ((`(,prog . ,args) (split-string line)))
|
||||
(and prog
|
||||
(string-match-p
|
||||
"\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog))
|
||||
(or (cl-loop for (opt val) on args
|
||||
if (string= opt "--socket")
|
||||
return val)
|
||||
(expand-file-name "~/.git-credential-cache/socket"))))
|
||||
;; Note: `magit-process-file' is not yet defined when
|
||||
;; evaluating this form, so we use `process-lines'.
|
||||
(ignore-errors
|
||||
(let ((process-environment
|
||||
(append magit-git-environment process-environment)))
|
||||
(process-lines magit-git-executable
|
||||
"config" "--get-all" "credential.helper"))))
|
||||
"\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog)
|
||||
(or (cl-loop for (opt val) on args
|
||||
if (string= opt "--socket")
|
||||
return val)
|
||||
(expand-file-name "~/.git-credential-cache/socket")))))
|
||||
;; Note: `magit-process-file' is not yet defined when
|
||||
;; evaluating this form, so we use `process-lines'.
|
||||
(ignore-errors
|
||||
(let ((process-environment
|
||||
(append magit-git-environment process-environment)))
|
||||
(process-lines magit-git-executable
|
||||
"config" "--get-all" "credential.helper"))))
|
||||
"If non-nil, start a credential cache daemon using this socket.
|
||||
|
||||
When using Git's cache credential helper in the normal way, Emacs
|
||||
@@ -152,32 +145,41 @@ itself from the hook, to avoid further futile attempts."
|
||||
(const :tag "Don't start a cache daemon" nil)))
|
||||
|
||||
(defcustom magit-process-yes-or-no-prompt-regexp
|
||||
(concat " [([]"
|
||||
"\\([Yy]\\(?:es\\)?\\)"
|
||||
"[/|]"
|
||||
"\\([Nn]o?\\)"
|
||||
;; OpenSSH v8 prints this. See #3969.
|
||||
"\\(?:/\\[fingerprint\\]\\)?"
|
||||
"[])] ?[?:]? ?$")
|
||||
(eval-when-compile
|
||||
(concat " [([]"
|
||||
"\\([Yy]\\(?:es\\)?\\)"
|
||||
"[/|]"
|
||||
"\\([Nn]o?\\)"
|
||||
;; OpenSSH v8 prints this. See #3969.
|
||||
"\\(?:/\\[fingerprint\\]\\)?"
|
||||
"[])] ?[?:]? ?$"))
|
||||
"Regexp matching Yes-or-No prompts of Git and its subprocesses."
|
||||
:package-version '(magit . "2.1.0")
|
||||
:group 'magit-process
|
||||
:type 'regexp)
|
||||
|
||||
(defcustom magit-process-password-prompt-regexps
|
||||
'("^\\(Enter \\)?[Pp]assphrase\\( for \\(RSA \\)?key '.*'\\)?: ?$"
|
||||
;; Match-group 99 is used to identify the "user@host" part.
|
||||
"^\\(Enter \\|([^) ]+) \\)?\
|
||||
[Pp]assword\\( for '?\\(https?://\\)?\\(?99:[^']*\\)'?\\)?: ?$"
|
||||
"Please enter the passphrase for the ssh key"
|
||||
"Please enter the passphrase to unlock the OpenPGP secret key"
|
||||
"^.*'s password: ?$"
|
||||
"^Token: $" ; For git-credential-manager-core (#4318).
|
||||
;; See also history in test `magit-process:password-prompt-regexps'.
|
||||
'(;; * CLI-prompt for passphrase for key:
|
||||
"^\\(\\(Please e\\|E\\)nter \\(the \\)?p\\|P\\)assphrase.*: ?$"
|
||||
;; * Password for something other than a host:
|
||||
"^\\(\\(Please e\\|E\\)nter \\(the \\)?p\\|P\\)assword: ?$"
|
||||
;; * Password for [user@]host (which we put in match group 99):
|
||||
"^\\(\\(Please e\\|E\\)nter \\(the \\)?p\\|P\\)assword for \
|
||||
[\"']?\\(https?://\\)?\\(?99:[^\"']+\\)[\"']?: ?$"
|
||||
"^(\\(?1:[^) ]+\\)) Password for \\(?99:\\1\\): ?$" ;#4992
|
||||
"^\\(?99:[^']+\\)\\('s\\)? password: ?$"
|
||||
;; * Token for git-credential-manager-core (#4318):
|
||||
"^Token: ?$"
|
||||
;; * Secret for card:
|
||||
"^Yubikey for .*: ?$"
|
||||
"^Enter PIN for .*: ?$")
|
||||
"^Enter PIN for .*: ?$"
|
||||
;; * Unanchored TUI-prompt for passphrase for key:
|
||||
"Please enter the passphrase for the ssh key"
|
||||
"Please enter the passphrase to unlock the OpenPGP secret key")
|
||||
"List of regexps matching password prompts of Git and its subprocesses.
|
||||
Also see `magit-process-find-password-functions'."
|
||||
:package-version '(magit . "3.0.0")
|
||||
:package-version '(magit . "4.3.0")
|
||||
:group 'magit-process
|
||||
:type '(repeat (regexp)))
|
||||
|
||||
@@ -198,7 +200,7 @@ non-nil, then the password is read from the user instead."
|
||||
:package-version '(magit . "2.3.0")
|
||||
:group 'magit-process
|
||||
:type 'hook
|
||||
:options '(magit-process-password-auth-source))
|
||||
:options (list #'magit-process-password-auth-source))
|
||||
|
||||
(defcustom magit-process-username-prompt-regexps
|
||||
'("^Username for '.*': ?$")
|
||||
@@ -257,6 +259,32 @@ string in the heading of its section."
|
||||
:group 'magit-process
|
||||
:type '(choice (const :tag "none" nil) string))
|
||||
|
||||
(defvar tramp-pipe-stty-settings)
|
||||
(defvar magit-tramp-pipe-stty-settings ""
|
||||
"Override `tramp-pipe-stty-settings' in `magit-start-process'.
|
||||
|
||||
The default for that Tramp variable is \"-icanon min 1 time 0\",
|
||||
which causes staging of individual hunks to hang. Using \"\"
|
||||
prevents that, but apparently has other issues, which is why it
|
||||
isn't the default.
|
||||
|
||||
This variable defaults to \"\" and is used to override the Tramp
|
||||
variable in `magit-start-process'. This only has an effect when
|
||||
using Tramp 2.6.2 or greater. This can also be set to `pty', in
|
||||
which case a pty is used instead of a pipe. That also prevents
|
||||
the hanging, but doesn't work for files with DOS line endings
|
||||
\(see #20).
|
||||
|
||||
For connections that have `tramp-direct-async-process' enabled,
|
||||
staging hunks hangs, unless this variable is set to `pty' (see
|
||||
#5220).
|
||||
|
||||
To fall back to the value of `tramp-pipe-stty-settings', set this
|
||||
variable to nil.
|
||||
|
||||
Also see https://github.com/magit/magit/issues/4720
|
||||
and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=62093.")
|
||||
|
||||
(defface magit-process-ok
|
||||
'((t :inherit magit-section-heading :foreground "green"))
|
||||
"Face for zero exit-status."
|
||||
@@ -284,12 +312,14 @@ Used when `magit-process-display-mode-line-error' is non-nil."
|
||||
(defvar-keymap magit-process-mode-map
|
||||
:doc "Keymap for `magit-process-mode'."
|
||||
:parent magit-mode-map
|
||||
"<remap> <magit-refresh>" #'undefined
|
||||
"<remap> <magit-delete-thing>" #'magit-process-kill)
|
||||
|
||||
(define-derived-mode magit-process-mode magit-mode "Magit Process"
|
||||
"Mode for looking at Git process output."
|
||||
:interactive nil
|
||||
:group 'magit-process
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(magit-hack-dir-local-variables)
|
||||
(setq magit--imenu-item-types 'process))
|
||||
|
||||
(defun magit-process-buffer (&optional nodisplay)
|
||||
@@ -307,10 +337,10 @@ optional NODISPLAY is non-nil also display it."
|
||||
(while (not (equal topdir prev))
|
||||
(setq prev topdir)
|
||||
(setq topdir (file-name-directory (directory-file-name topdir)))))))
|
||||
(let ((buffer (or (--first (with-current-buffer it
|
||||
(and (eq major-mode 'magit-process-mode)
|
||||
(equal default-directory topdir)))
|
||||
(buffer-list))
|
||||
(let ((buffer (or (seq-find (##with-current-buffer %
|
||||
(and (eq major-mode 'magit-process-mode)
|
||||
(equal default-directory topdir)))
|
||||
(buffer-list))
|
||||
(magit-generate-new-buffer 'magit-process-mode
|
||||
nil topdir))))
|
||||
(with-current-buffer buffer
|
||||
@@ -341,6 +371,27 @@ optional NODISPLAY is non-nil also display it."
|
||||
|
||||
(defvar magit-process-raise-error nil)
|
||||
|
||||
(defvar magit-process-record-invocations nil)
|
||||
(defvar magit-process-record-buffer-name " *magit-process-file record*")
|
||||
(defvar magit-process-record-entry-format "%T %%d $ %%a")
|
||||
|
||||
(defun magit-toggle-subprocess-record ()
|
||||
"Toggle whether subprocess invocations are recorded.
|
||||
|
||||
When enabled, all subprocesses started by `magit-process-file' are
|
||||
logged into the buffer specified by `magit-process-record-buffer-name'
|
||||
using the format `magit-process-record-entry-format'. This is for
|
||||
debugging purposes.
|
||||
|
||||
This is in addition to and distinct from the default logging done by
|
||||
default, and additional logging enabled with ~magit-toggle-git-debug~.
|
||||
|
||||
For alternatives, see info node `(magit)Debugging Tools'."
|
||||
(interactive)
|
||||
(setq magit-process-record-invocations (not magit-process-record-invocations))
|
||||
(message "Recording of subprocess invocations %s"
|
||||
(if magit-process-record-invocations "enabled" "disabled")))
|
||||
|
||||
(defun magit-git (&rest args)
|
||||
"Call Git synchronously in a separate process, for side-effects.
|
||||
|
||||
@@ -368,13 +419,13 @@ as well as the current repository's status buffer are refreshed.
|
||||
Process output goes into a new section in the buffer returned by
|
||||
`magit-process-buffer'."
|
||||
(let ((magit--refresh-cache (list (cons 0 0))))
|
||||
(magit-call-git args)
|
||||
(when (member (car args) '("init" "clone"))
|
||||
;; Creating a new repository invalidates the cache.
|
||||
(setq magit--refresh-cache nil))
|
||||
(magit-refresh)))
|
||||
(prog1 (magit-call-git args)
|
||||
(when (member (car args) '("init" "clone"))
|
||||
;; Creating a new repository invalidates the cache.
|
||||
(setq magit--refresh-cache nil))
|
||||
(magit-refresh))))
|
||||
|
||||
(defvar magit-pre-call-git-hook nil)
|
||||
(defvar magit-pre-call-git-hook (list #'magit-maybe-save-repository-buffers))
|
||||
|
||||
(defun magit-call-git (&rest args)
|
||||
"Call Git synchronously in a separate process.
|
||||
@@ -416,22 +467,24 @@ ensure unix eol conversion."
|
||||
|
||||
(defun magit-process-file (process &optional infile buffer display &rest args)
|
||||
"Process files synchronously in a separate process.
|
||||
Identical to `process-file' but temporarily enable Cygwin's
|
||||
\"noglob\" option during the call and ensure unix eol
|
||||
conversion."
|
||||
(when magit-process-extreme-logging
|
||||
(let ((inhibit-message t))
|
||||
(message "$ %s" (magit-process--format-arguments process args))))
|
||||
Similar to `process-file' but temporarily enable Cygwin's
|
||||
\"noglob\" option during the call and ensure unix eol conversion."
|
||||
(when magit-process-record-invocations
|
||||
(let ((messages-buffer-name magit-process-record-buffer-name)
|
||||
(inhibit-message t))
|
||||
(message "%s"
|
||||
(format-spec
|
||||
(format-time-string magit-process-record-entry-format)
|
||||
`((?d . ,(abbreviate-file-name default-directory))
|
||||
(?a . ,(magit-process--format-arguments process args)))))))
|
||||
(let ((process-environment (magit-process-environment))
|
||||
(default-process-coding-system (magit--process-coding-system)))
|
||||
(apply #'process-file process infile buffer display args)))
|
||||
|
||||
(defun magit-process-environment ()
|
||||
;; The various w32 hacks are only applicable when running on the
|
||||
;; local machine. As of Emacs 25.1, a local binding of
|
||||
;; process-environment different from the top-level value affects
|
||||
;; the environment used in
|
||||
;; tramp-sh-handle-{start-file-process,process-file}.
|
||||
;; The various w32 hacks are only applicable when running on the local
|
||||
;; machine. A local binding of process-environment different from the
|
||||
;; top-level value affects the environment used by Tramp.
|
||||
(let ((local (not (file-remote-p default-directory))))
|
||||
(append magit-git-environment
|
||||
(and local
|
||||
@@ -495,10 +548,10 @@ current when this function was called (if it is a Magit buffer
|
||||
and still alive), as well as the respective Magit status buffer.
|
||||
|
||||
See `magit-start-process' for more information."
|
||||
(message "Running %s %s" (magit-git-executable)
|
||||
(let ((m (mapconcat #'identity (flatten-tree args) " ")))
|
||||
(remove-list-of-text-properties 0 (length m) '(face) m)
|
||||
m))
|
||||
(magit-msg "Running %s %s" (magit-git-executable)
|
||||
(let ((m (string-join (flatten-tree args) " ")))
|
||||
(remove-list-of-text-properties 0 (length m) '(face) m)
|
||||
m))
|
||||
(magit-start-git nil args))
|
||||
|
||||
(defun magit-run-git-with-editor (&rest args)
|
||||
@@ -534,7 +587,7 @@ See `magit-start-process' and `with-editor' for more information."
|
||||
(set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel)
|
||||
magit-this-process)
|
||||
|
||||
(defvar magit-pre-start-git-hook nil)
|
||||
(defvar magit-pre-start-git-hook (list #'magit-maybe-save-repository-buffers))
|
||||
|
||||
(defun magit-start-git (input &rest args)
|
||||
"Start Git, prepare for refresh, and return the process object.
|
||||
@@ -580,10 +633,20 @@ Magit status buffer."
|
||||
((`(,process-buf . ,section)
|
||||
(magit-process-setup program args))
|
||||
(process
|
||||
(let ((process-connection-type
|
||||
;; Don't use a pty, because it would set icrnl
|
||||
;; which would modify the input (issue #20).
|
||||
(and (not input) magit-process-connection-type))
|
||||
(let ((process-connection-type ;t=pty nil=pipe
|
||||
(or
|
||||
;; With Tramp, maybe force use a pty. #4720
|
||||
(and (file-remote-p default-directory)
|
||||
(eq magit-tramp-pipe-stty-settings 'pty))
|
||||
;; Without input, don't use a pty, because it would
|
||||
;; set icrnl, which would modify the input. #20
|
||||
(and (not input) magit-process-connection-type)))
|
||||
(tramp-pipe-stty-settings
|
||||
(or (and (not (eq magit-tramp-pipe-stty-settings 'pty))
|
||||
;; Defaults to "", to allow staging hunks over
|
||||
;; Tramp again. #4720
|
||||
magit-tramp-pipe-stty-settings)
|
||||
(bound-and-true-p tramp-pipe-stty-settings)))
|
||||
(process-environment (magit-process-environment))
|
||||
(default-process-coding-system (magit--process-coding-system)))
|
||||
(apply #'start-file-process
|
||||
@@ -621,24 +684,32 @@ Magit status buffer."
|
||||
(defun magit-parse-git-async (&rest args)
|
||||
(setq args (magit-process-git-arguments args))
|
||||
(let ((command-buf (current-buffer))
|
||||
(process-buf (generate-new-buffer " *temp*"))
|
||||
(stdout-buf (generate-new-buffer " *git-stdout*"))
|
||||
(stderr-buf (generate-new-buffer " *git-stderr*"))
|
||||
(toplevel (magit-toplevel)))
|
||||
(with-current-buffer process-buf
|
||||
(with-current-buffer stdout-buf
|
||||
(setq default-directory toplevel)
|
||||
(let ((process
|
||||
(let ((process-connection-type nil)
|
||||
(process-environment (magit-process-environment))
|
||||
(default-process-coding-system
|
||||
(magit--process-coding-system)))
|
||||
(apply #'start-file-process "git" process-buf
|
||||
(magit-git-executable) args))))
|
||||
(let ((process-environment (magit-process-environment)))
|
||||
(make-process :name "git"
|
||||
:buffer stdout-buf
|
||||
:stderr stderr-buf
|
||||
:command (cons (magit-git-executable) args)
|
||||
:coding (magit--process-coding-system)
|
||||
:file-handler t))))
|
||||
(process-put process 'command-buf command-buf)
|
||||
(process-put process 'stderr-buf stderr-buf)
|
||||
(process-put process 'parsed (point))
|
||||
(setq magit-this-process process)
|
||||
process))))
|
||||
|
||||
;;; 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)
|
||||
(magit-process-set-mode-line program args)
|
||||
(let ((pwd default-directory)
|
||||
@@ -647,8 +718,10 @@ Magit status buffer."
|
||||
(prog1 (magit-process-insert-section pwd program args nil nil)
|
||||
(backward-char 1))))))
|
||||
|
||||
(defun magit-process-insert-section (pwd program args &optional errcode errlog)
|
||||
(defun magit-process-insert-section
|
||||
(pwd program args &optional errcode errlog face)
|
||||
(let ((inhibit-read-only t)
|
||||
(magit-insert-section--current nil)
|
||||
(magit-insert-section--parent magit-root-section)
|
||||
(magit-insert-section--oldroot nil))
|
||||
(goto-char (1- (point-max)))
|
||||
@@ -659,11 +732,14 @@ Magit status buffer."
|
||||
"run "))
|
||||
(when magit-process-timestamp-format
|
||||
(insert (format-time-string magit-process-timestamp-format) " "))
|
||||
(unless (equal (expand-file-name pwd)
|
||||
(expand-file-name default-directory))
|
||||
(insert (file-relative-name pwd default-directory) ?\s))
|
||||
(insert (magit-process--format-arguments program args))
|
||||
(magit-insert-heading)
|
||||
(let ((cmd (concat
|
||||
(and (not (equal
|
||||
(file-name-as-directory (expand-file-name pwd))
|
||||
(file-name-as-directory (expand-file-name
|
||||
default-directory))))
|
||||
(concat (file-relative-name pwd default-directory) " "))
|
||||
(magit-process--format-arguments program args))))
|
||||
(magit-insert-heading (if face (propertize cmd 'face face) cmd)))
|
||||
(when errlog
|
||||
(if (bufferp errlog)
|
||||
(insert (with-current-buffer errlog
|
||||
@@ -682,7 +758,7 @@ Magit status buffer."
|
||||
" "
|
||||
(propertize (magit--ellipsis)
|
||||
'font-lock-face 'magit-section-heading
|
||||
'help-echo (mapconcat #'identity (seq-take args global) " "))
|
||||
'help-echo (string-join (seq-take args global) " "))
|
||||
" "
|
||||
(propertize (mapconcat #'shell-quote-argument (seq-drop args global) " ")
|
||||
'font-lock-face 'magit-section-heading))))
|
||||
@@ -740,7 +816,7 @@ Magit status buffer."
|
||||
(when (memq (process-status process) '(exit signal))
|
||||
(magit-process-sentinel process event)
|
||||
(when-let* ((process-buf (process-buffer process))
|
||||
(- (buffer-live-p process-buf))
|
||||
((buffer-live-p process-buf))
|
||||
(status-buf (with-current-buffer process-buf
|
||||
(magit-get-mode-buffer 'magit-status-mode))))
|
||||
(with-current-buffer status-buf
|
||||
@@ -764,7 +840,7 @@ Magit status buffer."
|
||||
;; Find last ^M in string. If one was found, ignore
|
||||
;; everything before it and delete the current line.
|
||||
(when-let ((ret-pos (cl-position ?\r string :from-end t)))
|
||||
(cl-callf substring string (1+ ret-pos))
|
||||
(setq string (substring string (1+ ret-pos)))
|
||||
(delete-region (line-beginning-position) (point)))
|
||||
(setq string (magit-process-remove-bogus-errors string))
|
||||
(insert (propertize string 'magit-section
|
||||
@@ -831,10 +907,6 @@ PARENT is used as the parent of the returned keymap."
|
||||
"Use `auth-source-search' to get a password.
|
||||
If found, return the password. Otherwise, return nil.
|
||||
|
||||
To use this function add it to the appropriate hook
|
||||
(add-hook \\='magit-process-find-password-functions
|
||||
\\='magit-process-password-auth-source)
|
||||
|
||||
KEY typically derives from a prompt such as:
|
||||
Password for \\='https://yourname@github.com\\='
|
||||
in which case it would be the string
|
||||
@@ -851,7 +923,7 @@ respective documentation.
|
||||
|
||||
After manually editing ~/.authinfo.gpg you must reset
|
||||
the cache using
|
||||
M-x auth-source-forget-all-cached RET
|
||||
\\`M-x' `auth-source-forget-all-cached' \\`RET'
|
||||
|
||||
The above will save you from having to repeatedly type
|
||||
your token or password, but you might still repeatedly
|
||||
@@ -927,8 +999,8 @@ from the user."
|
||||
|
||||
(defun magit-process-match-prompt (prompts string)
|
||||
"Match STRING against PROMPTS and set match data.
|
||||
Return the matched string suffixed with \": \", if needed."
|
||||
(when (--any-p (string-match it string) prompts)
|
||||
Return the matched string, appending \": \" if needed."
|
||||
(when (seq-some (##string-match % string) prompts)
|
||||
(let ((prompt (match-string 0 string)))
|
||||
(cond ((string-suffix-p ": " prompt) prompt)
|
||||
((string-suffix-p ":" prompt) (concat prompt " "))
|
||||
@@ -960,12 +1032,13 @@ as argument."
|
||||
(memq magit-credential-cache-daemon-process
|
||||
(list-system-processes)))
|
||||
(setq magit-credential-cache-daemon-process
|
||||
(or (--first (let* ((attr (process-attributes it))
|
||||
(comm (cdr (assq 'comm attr)))
|
||||
(user (cdr (assq 'user attr))))
|
||||
(and (string= comm "git-credential-cache--daemon")
|
||||
(string= user user-login-name)))
|
||||
(list-system-processes))
|
||||
(or (seq-find (lambda (process)
|
||||
(let* ((attr (process-attributes process))
|
||||
(comm (cdr (assq 'comm attr)))
|
||||
(user (cdr (assq 'user attr))))
|
||||
(and (string= comm "git-credential-cache--daemon")
|
||||
(string= user user-login-name))))
|
||||
(list-system-processes))
|
||||
(condition-case nil
|
||||
(start-process "git-credential-cache--daemon"
|
||||
" *git-credential-cache--daemon*"
|
||||
@@ -980,32 +1053,9 @@ as argument."
|
||||
|
||||
(add-hook 'magit-credential-hook #'magit-maybe-start-credential-cache-daemon)
|
||||
|
||||
(defun tramp-sh-handle-start-file-process--magit-tramp-process-environment
|
||||
(fn name buffer program &rest args)
|
||||
(if magit-tramp-process-environment
|
||||
(apply fn name buffer
|
||||
(car magit-tramp-process-environment)
|
||||
(append (cdr magit-tramp-process-environment)
|
||||
(cons program args)))
|
||||
(apply fn name buffer program args)))
|
||||
|
||||
(advice-add 'tramp-sh-handle-start-file-process :around
|
||||
#'tramp-sh-handle-start-file-process--magit-tramp-process-environment)
|
||||
|
||||
(defun tramp-sh-handle-process-file--magit-tramp-process-environment
|
||||
(fn program &optional infile destination display &rest args)
|
||||
(if magit-tramp-process-environment
|
||||
(apply fn "env" infile destination display
|
||||
(append magit-tramp-process-environment
|
||||
(cons program args)))
|
||||
(apply fn program infile destination display args)))
|
||||
|
||||
(advice-add 'tramp-sh-handle-process-file :around
|
||||
#'tramp-sh-handle-process-file--magit-tramp-process-environment)
|
||||
|
||||
(defvar-keymap magit-mode-line-process-map
|
||||
:doc "Keymap for `mode-line-process'."
|
||||
"<mode-line> <mouse-1>" ''magit-process-buffer)
|
||||
"<mode-line> <mouse-1>" 'magit-process-buffer)
|
||||
|
||||
(defun magit-process-set-mode-line (program args)
|
||||
"Display the git command (sans arguments) in the mode line."
|
||||
@@ -1159,31 +1209,7 @@ Limited by `magit-process-error-tooltip-max-lines'."
|
||||
(dired-uncache default-dir))
|
||||
(when (buffer-live-p process-buf)
|
||||
(with-current-buffer process-buf
|
||||
(let ((inhibit-read-only t)
|
||||
(marker (oref section start)))
|
||||
(goto-char marker)
|
||||
(save-excursion
|
||||
(delete-char 3)
|
||||
(set-marker-insertion-type marker nil)
|
||||
(insert (propertize (format "%3s" arg)
|
||||
'magit-section section
|
||||
'font-lock-face (if (= arg 0)
|
||||
'magit-process-ok
|
||||
'magit-process-ng)))
|
||||
(set-marker-insertion-type marker t))
|
||||
(when magit-process-finish-apply-ansi-colors
|
||||
(ansi-color-apply-on-region (oref section content)
|
||||
(oref section end)))
|
||||
(if (= (oref section end)
|
||||
(+ (line-end-position) 2))
|
||||
(save-excursion
|
||||
(goto-char (1+ (line-end-position)))
|
||||
(delete-char -1)
|
||||
(oset section content nil))
|
||||
(when (and (= arg 0)
|
||||
(not (--any-p (eq (window-buffer it) process-buf)
|
||||
(window-list))))
|
||||
(magit-section-hide section))))))
|
||||
(magit-process-finish-section section arg)))
|
||||
(if (= arg 0)
|
||||
;; Unset the `mode-line-process' value upon success.
|
||||
(magit-process-unset-mode-line default-dir)
|
||||
@@ -1216,6 +1242,34 @@ Limited by `magit-process-error-tooltip-max-lines'."
|
||||
(buffer-name process-buf))))))
|
||||
arg)
|
||||
|
||||
(defun magit-process-finish-section (section exit-code)
|
||||
(let ((inhibit-read-only t)
|
||||
(buffer (current-buffer))
|
||||
(marker (oref section start)))
|
||||
(goto-char marker)
|
||||
(save-excursion
|
||||
(delete-char 3)
|
||||
(set-marker-insertion-type marker nil)
|
||||
(insert (propertize (format "%3s" exit-code)
|
||||
'magit-section section
|
||||
'font-lock-face (if (= exit-code 0)
|
||||
'magit-process-ok
|
||||
'magit-process-ng)))
|
||||
(set-marker-insertion-type marker t))
|
||||
(when magit-process-finish-apply-ansi-colors
|
||||
(ansi-color-apply-on-region (oref section content)
|
||||
(oref section end)))
|
||||
(if (= (oref section end)
|
||||
(+ (line-end-position) 2))
|
||||
(save-excursion
|
||||
(goto-char (1+ (line-end-position)))
|
||||
(delete-char -1)
|
||||
(oset section content nil))
|
||||
(when (and (= exit-code 0)
|
||||
(not (seq-some (##eq (window-buffer %) buffer)
|
||||
(window-list))))
|
||||
(magit-section-hide section)))))
|
||||
|
||||
(defun magit-process-display-buffer (process)
|
||||
(when (process-live-p process)
|
||||
(let ((buf (process-buffer process)))
|
||||
@@ -1253,7 +1307,7 @@ Limited by `magit-process-error-tooltip-max-lines'."
|
||||
(let ((inhibit-message t))
|
||||
(when heading
|
||||
(setq lines (cons heading lines)))
|
||||
(message (mapconcat #'identity lines "\n"))))))
|
||||
(message (string-join lines "\n"))))))
|
||||
|
||||
;;; _
|
||||
(provide 'magit-process)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-pull.el --- Update local objects and refs -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
(lambda () (if magit-pull-or-fetch "Pull arguments" "Arguments"))
|
||||
("-f" "Fast-forward only" "--ff-only")
|
||||
("-r" "Rebase local commits" ("-r" "--rebase"))
|
||||
("-A" "Autostash" "--autostash" :level 7)]
|
||||
("-A" "Autostash" "--autostash" :level 7)
|
||||
("-F" "Force" ("-f" "--force"))]
|
||||
[:description
|
||||
(lambda ()
|
||||
(if-let ((branch (magit-get-current-branch)))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-push.el --- Update remote objects and refs -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -87,10 +87,8 @@ argument the push-remote can be changed before pushed to it."
|
||||
(magit--select-push-remote "push there")))
|
||||
(when changed
|
||||
(magit-confirm 'set-and-push
|
||||
(string-replace
|
||||
"%" "%%"
|
||||
(format "Really use \"%s\" as push-remote and push \"%s\" there"
|
||||
remote branch))))
|
||||
(list "Really use \"%s\" as push-remote and push \"%s\" there"
|
||||
remote branch)))
|
||||
(run-hooks 'magit-credential-hook)
|
||||
(magit-run-git-async "push" "-v" args remote
|
||||
(format "refs/heads/%s:refs/heads/%s"
|
||||
@@ -130,8 +128,8 @@ the upstream."
|
||||
(not (or (magit-get-upstream-branch branch)
|
||||
(magit--unnamed-upstream-p remote merge)
|
||||
(magit--valid-upstream-p remote merge))))
|
||||
(let* ((branches (cl-union (--map (concat it "/" branch)
|
||||
(magit-list-remotes))
|
||||
(let* ((branches (cl-union (mapcar (##concat % "/" branch)
|
||||
(magit-list-remotes))
|
||||
(magit-list-remote-branch-names)
|
||||
:test #'equal))
|
||||
(upstream (magit-completing-read
|
||||
@@ -150,10 +148,8 @@ the upstream."
|
||||
;; is what the user wants to happen.
|
||||
(setq merge (concat "refs/heads/" merge)))
|
||||
(magit-confirm 'set-and-push
|
||||
(string-replace
|
||||
"%" "%%"
|
||||
(format "Really use \"%s\" as upstream and push \"%s\" there"
|
||||
upstream branch))))
|
||||
(list "Really use \"%s\" as upstream and push \"%s\" there"
|
||||
upstream branch)))
|
||||
(cl-pushnew "--set-upstream" args :test #'equal))
|
||||
(run-hooks 'magit-credential-hook)
|
||||
(magit-run-git-async "push" "-v" args remote (concat branch ":" merge))))
|
||||
@@ -309,7 +305,7 @@ what this command will do. To add it use something like:
|
||||
(let ((remotes (magit-list-remotes)))
|
||||
(cond
|
||||
((and (magit-git-version>= "2.27")
|
||||
(= (length remotes) 1))
|
||||
(length= remotes 1))
|
||||
(car remotes))
|
||||
((member "origin" remotes) "origin"))))))
|
||||
(if (null remote)
|
||||
@@ -340,9 +336,9 @@ what this command will do. To add it use something like:
|
||||
((not (string-match "/" ref))
|
||||
(magit--propertize-face (format "%s/%s" remote ref)
|
||||
'magit-branch-remote))
|
||||
(t (format "%s as %s"
|
||||
(magit--propertize-face remote 'bold)
|
||||
(magit--propertize-face ref 'bold)))))
|
||||
((format "%s as %s"
|
||||
(magit--propertize-face remote 'bold)
|
||||
(magit--propertize-face ref 'bold)))))
|
||||
"nothing (no upstream)")))
|
||||
("matching" (format "all matching to %s"
|
||||
(magit--propertize-face remote 'bold)))))))))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-reflog.el --- Inspect ref history -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -150,8 +150,9 @@ Type \\[magit-cherry-pick] to apply the commit at point.
|
||||
Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
|
||||
\\{magit-reflog-mode-map}"
|
||||
:interactive nil
|
||||
:group 'magit-log
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(magit-hack-dir-local-variables)
|
||||
(setq magit--imenu-item-types 'commit))
|
||||
|
||||
(defun magit-reflog-setup-buffer (ref)
|
||||
@@ -196,9 +197,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
command))
|
||||
(text (if (string= command "commit")
|
||||
label
|
||||
(mapconcat #'identity
|
||||
(delq nil (list command option type))
|
||||
" "))))
|
||||
(string-join (delq nil (list command option type)) " "))))
|
||||
(format "%-16s "
|
||||
(magit--propertize-face
|
||||
text (or (cdr (assoc label magit-reflog-labels))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-refs.el --- Listing references -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -42,11 +42,11 @@
|
||||
:type 'hook)
|
||||
|
||||
(defcustom magit-refs-sections-hook
|
||||
'(magit-insert-error-header
|
||||
magit-insert-branch-description
|
||||
magit-insert-local-branches
|
||||
magit-insert-remote-branches
|
||||
magit-insert-tags)
|
||||
(list #'magit-insert-error-header
|
||||
#'magit-insert-branch-description
|
||||
#'magit-insert-local-branches
|
||||
#'magit-insert-remote-branches
|
||||
#'magit-insert-tags)
|
||||
"Hook run to insert sections into a references buffer."
|
||||
:package-version '(magit . "2.1.0")
|
||||
:group 'magit-refs
|
||||
@@ -100,6 +100,15 @@ in the heading preceding the list of its branches."
|
||||
:group 'magit-refs
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom magit-refs-show-branch-descriptions nil
|
||||
"Whether to show the description, if any, of local branches.
|
||||
To distinguish branch descriptions from the commit summary of the tip,
|
||||
which is shown when there is no description or this option is disabled,
|
||||
descriptions use the bold face."
|
||||
:package-version '(magit . "4.3.0")
|
||||
:group 'magit-refs
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom magit-refs-margin
|
||||
(list nil
|
||||
(nth 1 magit-log-margin)
|
||||
@@ -141,7 +150,7 @@ tags."
|
||||
:group 'magit-margin
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom magit-refs-primary-column-width (cons 16 32)
|
||||
(defcustom magit-refs-primary-column-width '(16 . 32)
|
||||
"Width of the focus column in `magit-refs-mode' buffers.
|
||||
|
||||
The primary column is the column that contains the name of the
|
||||
@@ -238,7 +247,7 @@ the outcome.
|
||||
and lists of cherry commits relative to the reference at point
|
||||
instead of relative to the current buffer or `HEAD'.
|
||||
|
||||
Instead of adding this symbol, consider pressing \"C-u y o RET\".
|
||||
Instead of adding this symbol, consider pressing \\`C-u y o RET'.
|
||||
|
||||
`create-branch'
|
||||
|
||||
@@ -294,8 +303,9 @@ Type \\[magit-cherry-pick] to apply the commit at point.
|
||||
Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
|
||||
\\{magit-refs-mode-map}"
|
||||
:interactive nil
|
||||
:group 'magit-refs
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(magit-hack-dir-local-variables)
|
||||
(setq magit--imenu-group-types '(local remote tags)))
|
||||
|
||||
(defun magit-refs-setup-buffer (ref args)
|
||||
@@ -309,7 +319,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
(setq magit-refs-show-commit-count nil))
|
||||
(magit-set-header-line-format
|
||||
(format "%s %s" magit-buffer-upstream
|
||||
(mapconcat #'identity magit-buffer-arguments " ")))
|
||||
(string-join magit-buffer-arguments " ")))
|
||||
(magit-insert-section (branchbuf)
|
||||
(magit-run-section-hook 'magit-refs-sections-hook))
|
||||
(add-hook 'kill-buffer-hook #'magit-preserve-section-visibility-cache))
|
||||
@@ -357,7 +367,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
|
||||
(and-let* ((buffer (magit-get-mode-buffer
|
||||
'magit-refs-mode nil
|
||||
(eq use-buffer-args 'selected))))
|
||||
(progn ; work around debbugs#31840
|
||||
(progn
|
||||
(setq args (buffer-local-value 'magit-buffer-arguments buffer))
|
||||
t))))
|
||||
(t
|
||||
@@ -406,8 +416,12 @@ Compared with a branch read from the user."
|
||||
(magit-show-refs-arguments)))
|
||||
(magit-refs-setup-buffer ref args))
|
||||
|
||||
(defun magit-refs-set-show-commit-count ()
|
||||
(transient-define-suffix magit-refs-set-show-commit-count ()
|
||||
"Change for which refs the commit count is shown."
|
||||
:description "Change verbosity"
|
||||
:key "v"
|
||||
:transient nil
|
||||
:if-derived 'magit-refs-mode
|
||||
(interactive)
|
||||
(setq-local magit-refs-show-commit-count
|
||||
(magit-read-char-case "Show commit counts for " nil
|
||||
@@ -523,7 +537,7 @@ line is inserted at all."
|
||||
(magit-insert-section (branchdesc branch t)
|
||||
(magit-insert-heading branch ": " (car desc))
|
||||
(when (cdr desc)
|
||||
(insert (mapconcat #'identity (cdr desc) "\n"))
|
||||
(insert (string-join (cdr desc) "\n"))
|
||||
(insert "\n\n")))))
|
||||
|
||||
(defun magit-insert-tags ()
|
||||
@@ -531,7 +545,7 @@ line is inserted at all."
|
||||
(when-let ((tags (magit-git-lines "tag" "--list" "-n" magit-buffer-arguments)))
|
||||
(let ((_head (magit-rev-parse "HEAD")))
|
||||
(magit-insert-section (tags)
|
||||
(magit-insert-heading "Tags:")
|
||||
(magit-insert-heading (length tags) "Tags")
|
||||
(dolist (tag tags)
|
||||
(string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag)
|
||||
(let ((tag (match-string 1 tag))
|
||||
@@ -547,7 +561,7 @@ line is inserted at all."
|
||||
magit-refs-primary-column-width)
|
||||
(length tag)))
|
||||
?\s)
|
||||
(and msg (magit-log-propertize-keywords nil msg)))
|
||||
(and msg (magit-log--wash-summary msg)))
|
||||
(when (and magit-refs-margin-for-tags (magit-buffer-margin-p))
|
||||
(magit-refs--format-margin tag))
|
||||
(magit-refs--insert-cherry-commits tag)))))
|
||||
@@ -574,14 +588,18 @@ line is inserted at all."
|
||||
(cl-substitute nil ""
|
||||
(split-string line "\0")
|
||||
:test #'equal)))
|
||||
(if head-branch
|
||||
;; Note: Use `ref' instead of `branch' for the check
|
||||
;; below because 'refname:short' shortens the remote
|
||||
;; HEAD to '<remote>' instead of '<remote>/HEAD' as of
|
||||
;; Git v2.40.0.
|
||||
(progn (cl-assert
|
||||
(equal ref (concat "refs/remotes/" remote "/HEAD")))
|
||||
(setq head head-branch))
|
||||
(cond
|
||||
(head-branch
|
||||
;; Note: Use `ref' instead of `branch' for the check
|
||||
;; below because 'refname:short' shortens the remote
|
||||
;; HEAD to '<remote>' instead of '<remote>/HEAD' as of
|
||||
;; Git v2.40.0.
|
||||
(cl-assert
|
||||
(equal ref (concat "refs/remotes/" remote "/HEAD")))
|
||||
(setq head head-branch))
|
||||
((not (equal ref (concat "refs/remotes/" remote "/HEAD")))
|
||||
;; ^ Skip mis-configured remotes where HEAD is not a
|
||||
;; symref. See #5092.
|
||||
(when (magit-refs--insert-refname-p branch)
|
||||
(magit-insert-section (branch branch t)
|
||||
(let ((headp (equal branch head))
|
||||
@@ -598,23 +616,23 @@ line is inserted at all."
|
||||
magit-refs-primary-column-width)
|
||||
(length abbrev)))
|
||||
?\s)
|
||||
(and msg (magit-log-propertize-keywords nil msg))))
|
||||
(and msg (magit-log--wash-summary msg))))
|
||||
(when (magit-buffer-margin-p)
|
||||
(magit-refs--format-margin branch))
|
||||
(magit-refs--insert-cherry-commits branch)))))))
|
||||
(magit-refs--insert-cherry-commits branch))))))))
|
||||
(insert ?\n)
|
||||
(magit-make-margin-overlay nil t))))
|
||||
|
||||
(defun magit-insert-local-branches ()
|
||||
"Insert sections showing all local branches."
|
||||
(magit-insert-section (local nil)
|
||||
(magit-insert-heading "Branches:")
|
||||
(magit-insert-heading t "Branches")
|
||||
(dolist (line (magit-refs--format-local-branches))
|
||||
(pcase-let ((`(,branch . ,strings) line))
|
||||
(magit-insert-section
|
||||
((eval (if branch 'branch 'commit))
|
||||
(or branch (magit-rev-parse "HEAD"))
|
||||
t)
|
||||
((eval (if branch 'branch 'commit))
|
||||
(or branch (magit-rev-parse "HEAD"))
|
||||
t)
|
||||
(apply #'magit-insert-heading strings)
|
||||
(when (magit-buffer-margin-p)
|
||||
(magit-refs--format-margin branch))
|
||||
@@ -631,7 +649,7 @@ line is inserted at all."
|
||||
%(upstream:short)%00%(upstream)%00%(upstream:track)%00"
|
||||
(if magit-refs-show-push-remote "\
|
||||
%(push:remotename)%00%(push)%00%(push:track)%00%(subject)"
|
||||
"%00%00%00%(subject)"))
|
||||
"%00%00%00%(subject)"))
|
||||
"refs/heads"
|
||||
magit-buffer-arguments))))
|
||||
(unless (magit-get-current-branch)
|
||||
@@ -644,8 +662,9 @@ line is inserted at all."
|
||||
def
|
||||
(pcase-let ((`(,min . ,max) def))
|
||||
(min max (apply #'max min (mapcar #'car lines)))))))
|
||||
(mapcar (pcase-lambda (`(,_ ,branch ,focus ,branch-desc ,u:ahead ,p:ahead
|
||||
,u:behind ,upstream ,p:behind ,push ,msg))
|
||||
(mapcar (pcase-lambda (`( ,_ ,branch ,focus
|
||||
,branch-desc ,u:ahead ,p:ahead
|
||||
,u:behind ,upstream ,p:behind ,msg))
|
||||
(list branch focus branch-desc u:ahead p:ahead
|
||||
(make-string (max 1 (- magit-refs-primary-column-width
|
||||
(length (concat branch-desc
|
||||
@@ -653,8 +672,7 @@ line is inserted at all."
|
||||
p:ahead
|
||||
u:behind))))
|
||||
?\s)
|
||||
u:behind upstream p:behind push
|
||||
msg))
|
||||
u:behind upstream p:behind msg))
|
||||
lines)))
|
||||
|
||||
(defun magit-refs--format-local-branch (line)
|
||||
@@ -668,7 +686,7 @@ line is inserted at all."
|
||||
magit-refs-show-push-remote
|
||||
(magit-rev-verify p:ref)
|
||||
(not (equal p:ref u:ref))))
|
||||
(branch-desc
|
||||
(branch-pretty
|
||||
(if branch
|
||||
(magit-refs--propertize-branch
|
||||
branch ref (and headp 'magit-branch-current))
|
||||
@@ -701,10 +719,11 @@ line is inserted at all."
|
||||
(match-string 1 p:track)
|
||||
(and magit-refs-pad-commit-counts " "))
|
||||
'magit-dimmed))))
|
||||
(list (1+ (length (concat branch-desc u:ahead p:ahead u:behind)))
|
||||
(list (1+ (length (concat branch-pretty u:ahead p:ahead u:behind)))
|
||||
branch
|
||||
(magit-refs--format-focus-column branch headp)
|
||||
branch-desc u:ahead p:ahead u:behind
|
||||
branch-pretty u:ahead p:ahead
|
||||
u:behind
|
||||
(and upstream
|
||||
(concat (if (equal u:track "[gone]")
|
||||
(magit--propertize-face upstream 'error)
|
||||
@@ -715,7 +734,10 @@ line is inserted at all."
|
||||
(magit--propertize-face
|
||||
push 'magit-branch-remote)
|
||||
" "))
|
||||
(and msg (magit-log-propertize-keywords nil msg)))))))
|
||||
(if-let ((magit-refs-show-branch-descriptions)
|
||||
(desc (magit-get "branch" branch "description")))
|
||||
(magit--propertize-face desc 'bold)
|
||||
(and msg (magit-log--wash-summary msg))))))))
|
||||
|
||||
(defun magit-refs--format-focus-column (ref &optional type)
|
||||
(let ((focus magit-buffer-upstream)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-remote.el --- Transfer Git commits -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -68,9 +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
|
||||
(oref transient--prefix scope)))
|
||||
:if (lambda () (and magit-remote-direct-configure (transient-scope)))
|
||||
("u" magit-remote.<remote>.url)
|
||||
("U" magit-remote.<remote>.fetch)
|
||||
("s" magit-remote.<remote>.pushurl)
|
||||
@@ -85,8 +83,8 @@ has to be used to view and change remote related variables."
|
||||
[("C" "Configure..." magit-remote-configure)
|
||||
("p" "Prune stale branches" magit-remote-prune)
|
||||
("P" "Prune stale refspecs" magit-remote-prune-refspecs)
|
||||
("b" magit-update-default-branch)
|
||||
(7 "z" "Unshallow remote" magit-remote-unshallow)]]
|
||||
(7 "z" "Unshallow remote" magit-remote-unshallow)]
|
||||
[("d u" magit-update-default-branch)]]
|
||||
(interactive (list (magit-get-current-remote)))
|
||||
(transient-setup 'magit-remote nil nil :scope remote))
|
||||
|
||||
@@ -181,12 +179,13 @@ the now stale refspecs. Other stale branches are not removed."
|
||||
(ours (match-string 3 refspec)))
|
||||
(unless (if (string-match "\\*" theirs)
|
||||
(let ((re (replace-match ".*" t t theirs)))
|
||||
(--some (string-match-p re it) remote-refs))
|
||||
(seq-some (##string-match-p re %) remote-refs))
|
||||
(member theirs remote-refs))
|
||||
(push (cons refspec
|
||||
(if (string-match "\\*" ours)
|
||||
(let ((re (replace-match ".*" t t ours)))
|
||||
(--filter (string-match-p re it) tracking-refs))
|
||||
(seq-filter (##string-match-p re %)
|
||||
tracking-refs))
|
||||
(list (car (member ours tracking-refs)))))
|
||||
stale)))))
|
||||
(if (not stale)
|
||||
@@ -201,18 +200,18 @@ the now stale refspecs. Other stale branches are not removed."
|
||||
variable))
|
||||
(?r "[r]emove remote"
|
||||
(magit-call-git "remote" "rm" remote))
|
||||
(?a "or [a]abort"
|
||||
(?a "[a]abort"
|
||||
(user-error "Abort")))
|
||||
(if (if (length= stale 1)
|
||||
(pcase-let ((`(,refspec . ,refs) (car stale)))
|
||||
(magit-confirm 'prune-stale-refspecs
|
||||
(format "Prune stale refspec %s and branch %%s" refspec)
|
||||
(format "Prune stale refspec %s and %%d branches" refspec)
|
||||
(list "Prune stale refspec %s and branch %%s" refspec)
|
||||
(list "Prune stale refspec %s and %%d branches" refspec)
|
||||
nil refs))
|
||||
(magit-confirm 'prune-stale-refspecs nil
|
||||
(format "Prune %%d stale refspecs and %d branches"
|
||||
(length (cl-mapcan (lambda (s) (copy-sequence (cdr s)))
|
||||
stale)))
|
||||
(length (mapcan (lambda (s) (copy-sequence (cdr s)))
|
||||
stale)))
|
||||
nil
|
||||
(mapcar (pcase-lambda (`(,refspec . ,refs))
|
||||
(concat refspec "\n"
|
||||
@@ -282,8 +281,8 @@ Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\"."
|
||||
newname)
|
||||
newname "master")))
|
||||
(cond
|
||||
((y-or-n-p (format "Default branch changed from `%s' to `%s' on %s.%s"
|
||||
oldname newname remote " Do the same locally? "))
|
||||
((y-or-n-p (format "Default branch changed from `%s' to `%s' on %s.%s?"
|
||||
oldname newname remote " Do the same locally"))
|
||||
(magit--set-default-branch newname oldname)
|
||||
(magit-refresh))
|
||||
((user-error "Abort")))))))
|
||||
@@ -314,9 +313,8 @@ refspec."
|
||||
:man-page "git-remote"
|
||||
[:description
|
||||
(lambda ()
|
||||
(concat
|
||||
(propertize "Configure " 'face 'transient-heading)
|
||||
(propertize (oref transient--prefix scope) 'face 'magit-branch-remote)))
|
||||
(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)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-repos.el --- Listing repositories -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -56,27 +56,29 @@ This option controls which repositories are being listed by
|
||||
:link '(info-link "(magit)Repository List")
|
||||
:group 'magit-modes)
|
||||
|
||||
(defcustom magit-repolist-mode-hook '(hl-line-mode)
|
||||
(defcustom magit-repolist-mode-hook (list #'hl-line-mode)
|
||||
"Hook run after entering Magit-Repolist mode."
|
||||
:package-version '(magit . "2.9.0")
|
||||
:group 'magit-repolist
|
||||
:type 'hook
|
||||
:get #'magit-hook-custom-get
|
||||
:options '(hl-line-mode))
|
||||
:options (list #'hl-line-mode))
|
||||
|
||||
(defcustom magit-repolist-columns
|
||||
'(("Name" 25 magit-repolist-column-ident nil)
|
||||
("Version" 25 magit-repolist-column-version
|
||||
`(("Name" 25 ,#'magit-repolist-column-ident
|
||||
())
|
||||
("Version" 25 ,#'magit-repolist-column-version
|
||||
((:sort magit-repolist-version<)))
|
||||
("B<U" 3 magit-repolist-column-unpulled-from-upstream
|
||||
("B<U" 3 ,#'magit-repolist-column-unpulled-from-upstream
|
||||
(;; (:help-echo "Upstream changes not in branch")
|
||||
(:right-align t)
|
||||
(:sort <)))
|
||||
("B>U" 3 magit-repolist-column-unpushed-to-upstream
|
||||
("B>U" 3 ,#'magit-repolist-column-unpushed-to-upstream
|
||||
(;; (:help-echo "Local changes not in upstream")
|
||||
(:right-align t)
|
||||
(:sort <)))
|
||||
("Path" 99 magit-repolist-column-path nil))
|
||||
("Path" 99 ,#'magit-repolist-column-path
|
||||
()))
|
||||
"List of columns displayed by `magit-list-repositories'.
|
||||
|
||||
Each element has the form (HEADER WIDTH FORMAT PROPS).
|
||||
@@ -116,9 +118,9 @@ than 9."
|
||||
(sexp :tag "Value"))))))
|
||||
|
||||
(defcustom magit-repolist-column-flag-alist
|
||||
'((magit-untracked-files . "N")
|
||||
(magit-unstaged-files . "U")
|
||||
(magit-staged-files . "S"))
|
||||
`((,#'magit-untracked-files . "N")
|
||||
(,#'magit-unstaged-files . "U")
|
||||
(,#'magit-staged-files . "S"))
|
||||
"Association list of predicates and flags for `magit-repolist-column-flag'.
|
||||
|
||||
Each element is of the form (FUNCTION . FLAG). Each FUNCTION is
|
||||
@@ -178,14 +180,14 @@ repositories are displayed."
|
||||
"Fetch all marked or listed repositories."
|
||||
(interactive (list (magit-repolist--get-repos ?*)))
|
||||
(run-hooks 'magit-credential-hook)
|
||||
(magit-repolist--mapc (apply-partially #'magit-run-git "remote" "update")
|
||||
(magit-repolist--mapc (##magit-run-git "remote" "update")
|
||||
repos "Fetching in %s..."))
|
||||
|
||||
(defun magit-repolist-find-file-other-frame (repos file)
|
||||
"Find a file in all marked or listed repositories."
|
||||
(interactive (list (magit-repolist--get-repos ?*)
|
||||
(read-string "Find file in repositories: ")))
|
||||
(magit-repolist--mapc (apply-partially #'find-file-other-frame file) repos))
|
||||
(magit-repolist--mapc (##find-file-other-frame file) repos))
|
||||
|
||||
(defun magit-repolist--ensure-padding ()
|
||||
"Set `tabulated-list-padding' to 2, unless that is already non-zero."
|
||||
@@ -240,17 +242,16 @@ If it contains \"%s\" then the directory is substituted for that."
|
||||
(let ((base default-directory)
|
||||
(len (length repos))
|
||||
(i 0))
|
||||
(mapc (lambda (repo)
|
||||
(let ((default-directory
|
||||
(file-name-as-directory (expand-file-name repo base))))
|
||||
(if msg
|
||||
(let ((msg (concat (format "(%s/%s) " (cl-incf i) len)
|
||||
(format msg default-directory))))
|
||||
(message msg)
|
||||
(funcall fn)
|
||||
(message (concat msg "done")))
|
||||
(funcall fn))))
|
||||
repos)))
|
||||
(dolist (repo repos)
|
||||
(let ((default-directory
|
||||
(file-name-as-directory (expand-file-name repo base))))
|
||||
(if msg
|
||||
(let ((msg (concat (format "(%s/%s) " (cl-incf i) len)
|
||||
(format msg default-directory))))
|
||||
(message msg)
|
||||
(funcall fn)
|
||||
(message (concat msg "done")))
|
||||
(funcall fn))))))
|
||||
|
||||
;;;; Mode
|
||||
|
||||
@@ -265,9 +266,11 @@ If it contains \"%s\" then the directory is substituted for that."
|
||||
|
||||
(define-derived-mode magit-repolist-mode tabulated-list-mode "Repos"
|
||||
"Major mode for browsing a list of Git repositories."
|
||||
:interactive nil
|
||||
:group 'magit-repolist
|
||||
(setq-local x-stretch-cursor nil)
|
||||
(setq tabulated-list-padding 0)
|
||||
(add-hook 'tabulated-list-revert-hook #'magit-repolist-refresh nil t)
|
||||
(setq-local tabulated-list-revert-hook (list #'magit-repolist-refresh t))
|
||||
(setq imenu-prev-index-position-function
|
||||
#'magit-repolist--imenu-prev-index-position)
|
||||
(setq imenu-extract-index-name-function #'tabulated-list-get-id))
|
||||
@@ -323,9 +326,9 @@ If it contains \"%s\" then the directory is substituted for that."
|
||||
""))
|
||||
magit-repolist-columns)))))
|
||||
(magit-list-repos-uniquify
|
||||
(--map (cons (file-name-nondirectory (directory-file-name it))
|
||||
it)
|
||||
(magit-list-repos)))))
|
||||
(mapcar (##cons (file-name-nondirectory (directory-file-name %))
|
||||
%)
|
||||
(magit-list-repos)))))
|
||||
(message "Listing repositories...")
|
||||
(tabulated-list-init-header)
|
||||
(tabulated-list-print t)
|
||||
@@ -379,7 +382,8 @@ Usually this is just its basename."
|
||||
(when (match-end 2)
|
||||
(magit--put-face (match-beginning 2) (match-end 2) 'bold v))
|
||||
(when (match-end 4)
|
||||
(magit--put-face (match-beginning 4) (match-end 4) 'error v))
|
||||
(magit--put-face (or (match-beginning 3) (match-beginning 4))
|
||||
(match-end 4) 'error v))
|
||||
(when (and (equal (match-string 2 v) "1")
|
||||
(string-match-p magit-repolist-column-version-resume-regexp
|
||||
(magit-rev-format "%s")))
|
||||
@@ -497,18 +501,18 @@ instead."
|
||||
(or (magit-toplevel) default-directory)))))
|
||||
|
||||
(defun magit-list-repos ()
|
||||
(cl-mapcan (pcase-lambda (`(,dir . ,depth))
|
||||
(magit-list-repos-1 dir depth))
|
||||
magit-repository-directories))
|
||||
(mapcan (pcase-lambda (`(,dir . ,depth))
|
||||
(magit-list-repos-1 dir depth))
|
||||
magit-repository-directories))
|
||||
|
||||
(defun magit-list-repos-1 (directory depth)
|
||||
(cond ((file-readable-p (expand-file-name ".git" directory))
|
||||
(list (file-name-as-directory directory)))
|
||||
((and (> depth 0) (magit-file-accessible-directory-p directory))
|
||||
(--mapcat (and (file-directory-p it)
|
||||
(magit-list-repos-1 it (1- depth)))
|
||||
(directory-files directory t
|
||||
directory-files-no-dot-files-regexp t)))))
|
||||
((and (> depth 0) (file-accessible-directory-p directory))
|
||||
(mapcan (##and (file-directory-p %)
|
||||
(magit-list-repos-1 % (1- depth)))
|
||||
(directory-files directory t
|
||||
directory-files-no-dot-files-regexp t)))))
|
||||
|
||||
(defun magit-list-repos-uniquify (alist)
|
||||
(let (result (dict (make-hash-table :test #'equal)))
|
||||
@@ -519,22 +523,24 @@ instead."
|
||||
(if (length= value 1)
|
||||
(push (cons key (car value)) result)
|
||||
(setq result
|
||||
(append result
|
||||
(magit-list-repos-uniquify
|
||||
(--map (cons (concat
|
||||
key "\\"
|
||||
(file-name-nondirectory
|
||||
(directory-file-name
|
||||
(substring it 0 (- (1+ (length key)))))))
|
||||
it)
|
||||
value))))))
|
||||
(append
|
||||
result
|
||||
(magit-list-repos-uniquify
|
||||
(mapcar (lambda (v)
|
||||
(cons (concat
|
||||
key "\\"
|
||||
(file-name-nondirectory
|
||||
(directory-file-name
|
||||
(substring v 0 (- (1+ (length key)))))))
|
||||
v))
|
||||
value))))))
|
||||
dict)
|
||||
result))
|
||||
|
||||
(defun magit-repos-alist ()
|
||||
(magit-list-repos-uniquify
|
||||
(--map (cons (file-name-nondirectory (directory-file-name it)) it)
|
||||
(magit-list-repos))))
|
||||
(mapcar (##cons (file-name-nondirectory (directory-file-name %)) %)
|
||||
(magit-list-repos))))
|
||||
|
||||
;;; _
|
||||
(provide 'magit-repos)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-reset.el --- Reset functionality -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-sequence.el --- History manipulation in Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -91,31 +91,36 @@
|
||||
(defun magit-sequencer-continue ()
|
||||
"Resume the current cherry-pick or revert sequence."
|
||||
(interactive)
|
||||
(if (magit-sequencer-in-progress-p)
|
||||
(if (magit-anything-unmerged-p)
|
||||
(user-error "Cannot continue due to unresolved conflicts")
|
||||
(magit-run-git-sequencer
|
||||
(if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue"))
|
||||
(user-error "No cherry-pick or revert in progress")))
|
||||
(cond
|
||||
((not (magit-sequencer-in-progress-p))
|
||||
(user-error "No cherry-pick or revert in progress"))
|
||||
((magit-anything-unmerged-p)
|
||||
(user-error "Cannot continue due to unresolved conflicts"))
|
||||
((magit-run-git-sequencer
|
||||
(if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-sequencer-skip ()
|
||||
"Skip the stopped at commit during a cherry-pick or revert sequence."
|
||||
(interactive)
|
||||
(if (magit-sequencer-in-progress-p)
|
||||
(progn (magit-call-git "reset" "--hard")
|
||||
(magit-sequencer-continue))
|
||||
(user-error "No cherry-pick or revert in progress")))
|
||||
(unless (magit-sequencer-in-progress-p)
|
||||
(user-error "No cherry-pick or revert in progress"))
|
||||
(magit-call-git "reset" "--hard")
|
||||
(magit-sequencer-continue))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-sequencer-abort ()
|
||||
"Abort the current cherry-pick or revert sequence.
|
||||
This discards all changes made since the sequence started."
|
||||
(interactive)
|
||||
(if (magit-sequencer-in-progress-p)
|
||||
(magit-run-git-sequencer
|
||||
(if (magit-revert-in-progress-p) "revert" "cherry-pick") "--abort")
|
||||
(user-error "No cherry-pick or revert in progress")))
|
||||
(cond
|
||||
((not (magit-sequencer-in-progress-p))
|
||||
(user-error "No cherry-pick or revert in progress"))
|
||||
((magit-revert-in-progress-p)
|
||||
(magit-confirm 'abort-revert "Really abort revert")
|
||||
(magit-run-git-sequencer "revert" "--abort"))
|
||||
((magit-confirm 'abort-cherry-pick "Really abort cherry-pick")
|
||||
(magit-run-git-sequencer "cherry-pick" "--abort"))))
|
||||
|
||||
(defun magit-sequencer-in-progress-p ()
|
||||
(or (magit-cherry-pick-in-progress-p)
|
||||
@@ -139,8 +144,8 @@ This discards all changes made since the sequence started."
|
||||
("-F" "Attempt fast-forward" "--ff")
|
||||
("-x" "Reference cherry in commit message" "-x")
|
||||
("-e" "Edit commit messages" ("-e" "--edit"))
|
||||
("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
|
||||
(5 magit:--gpg-sign)]
|
||||
(magit:--gpg-sign)
|
||||
(magit:--signoff)]
|
||||
[:if-not magit-sequencer-in-progress-p
|
||||
["Apply here"
|
||||
("A" "Pick" magit-cherry-copy)
|
||||
@@ -338,11 +343,11 @@ the process manually."
|
||||
(let ((merges (seq-filter #'magit-merge-commit-p commits)))
|
||||
(cond
|
||||
((not merges)
|
||||
(--remove (string-prefix-p "--mainline=" it) args))
|
||||
(seq-remove (##string-prefix-p "--mainline=" %) args))
|
||||
((cl-set-difference commits merges :test #'equal)
|
||||
(user-error "Cannot %s merge and non-merge commits at once"
|
||||
command))
|
||||
((--first (string-prefix-p "--mainline=" it) args)
|
||||
((seq-find (##string-prefix-p "--mainline=" %) args)
|
||||
args)
|
||||
(t
|
||||
(cons (format "--mainline=%s"
|
||||
@@ -373,8 +378,8 @@ the process manually."
|
||||
("-e" "Edit commit message" ("-e" "--edit"))
|
||||
("-E" "Don't edit commit message" "--no-edit")
|
||||
("=s" magit-merge:--strategy)
|
||||
("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
|
||||
(5 magit:--gpg-sign)]
|
||||
(magit:--gpg-sign)
|
||||
(magit:--signoff)]
|
||||
["Actions"
|
||||
:if-not magit-sequencer-in-progress-p
|
||||
("V" "Revert commit(s)" magit-revert-and-commit)
|
||||
@@ -434,8 +439,8 @@ without prompting."
|
||||
("-b" "Limit removal of email cruft" "--keep-non-patch")
|
||||
("-d" "Use author date as committer date" "--committer-date-is-author-date")
|
||||
("-t" "Use current time as author date" "--ignore-date")
|
||||
("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
|
||||
(5 magit:--gpg-sign)]
|
||||
(magit:--gpg-sign)
|
||||
(magit:--signoff)]
|
||||
["Apply"
|
||||
:if-not magit-am-in-progress-p
|
||||
("m" "maildir" magit-am-apply-maildir)
|
||||
@@ -469,9 +474,9 @@ without prompting."
|
||||
nil default))))
|
||||
(magit-am-arguments)))
|
||||
(magit-run-git-sequencer "am" args "--"
|
||||
(--map (magit-convert-filename-for-git
|
||||
(expand-file-name it))
|
||||
files)))
|
||||
(mapcar (##magit-convert-filename-for-git
|
||||
(expand-file-name %))
|
||||
files)))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-am-apply-maildir (&optional maildir args)
|
||||
@@ -485,28 +490,29 @@ without prompting."
|
||||
(defun magit-am-continue ()
|
||||
"Resume the current patch applying sequence."
|
||||
(interactive)
|
||||
(if (magit-am-in-progress-p)
|
||||
(if (magit-anything-unstaged-p t)
|
||||
(error "Cannot continue due to unstaged changes")
|
||||
(magit-run-git-sequencer "am" "--continue"))
|
||||
(user-error "Not applying any patches")))
|
||||
(cond
|
||||
((not (magit-am-in-progress-p))
|
||||
(user-error "Not applying any patches"))
|
||||
((magit-anything-unstaged-p t)
|
||||
(user-error "Cannot continue due to unstaged changes"))
|
||||
((magit-run-git-sequencer "am" "--continue"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-am-skip ()
|
||||
"Skip the stopped at patch during a patch applying sequence."
|
||||
(interactive)
|
||||
(if (magit-am-in-progress-p)
|
||||
(magit-run-git-sequencer "am" "--skip")
|
||||
(user-error "Not applying any patches")))
|
||||
(unless (magit-am-in-progress-p)
|
||||
(user-error "Not applying any patches"))
|
||||
(magit-run-git-sequencer "am" "--skip"))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-am-abort ()
|
||||
"Abort the current patch applying sequence.
|
||||
This discards all changes made since the sequence started."
|
||||
(interactive)
|
||||
(if (magit-am-in-progress-p)
|
||||
(magit-run-git "am" "--abort")
|
||||
(user-error "Not applying any patches")))
|
||||
(unless (magit-am-in-progress-p)
|
||||
(user-error "Not applying any patches"))
|
||||
(magit-run-git "am" "--abort"))
|
||||
|
||||
(defun magit-am-in-progress-p ()
|
||||
(file-exists-p (expand-file-name "rebase-apply/applying" (magit-gitdir))))
|
||||
@@ -524,8 +530,7 @@ This discards all changes made since the sequence started."
|
||||
("-p" "Preserve merges" ("-p" "--preserve-merges")
|
||||
:if (lambda () (magit-git-version< "2.33.0")))
|
||||
("-r" "Rebase merges" ("-r" "--rebase-merges=")
|
||||
magit-rebase-merges-select-mode
|
||||
:if (lambda () (magit-git-version>= "2.18.0")))
|
||||
magit-rebase-merges-select-mode)
|
||||
("-u" "Update branches" "--update-refs"
|
||||
:if (lambda () (magit-git-version>= "2.38.0")))
|
||||
(7 magit-merge:--strategy)
|
||||
@@ -539,7 +544,8 @@ This discards all changes made since the sequence started."
|
||||
("-i" "Interactive" ("-i" "--interactive"))
|
||||
("-h" "Disable hooks" "--no-verify")
|
||||
(7 magit-rebase:--exec)
|
||||
(5 magit:--gpg-sign)]
|
||||
(magit:--gpg-sign)
|
||||
(magit:--signoff)]
|
||||
[:if-not magit-rebase-in-progress-p
|
||||
:description (lambda ()
|
||||
(format (propertize "Rebase %s onto" 'face 'transient-heading)
|
||||
@@ -683,7 +689,7 @@ START has to be selected from a list of recent commits."
|
||||
(when (and commit (not noassert))
|
||||
(setq commit (magit-rebase-interactive-assert
|
||||
commit delay-edit-confirm
|
||||
(--some (string-prefix-p "--rebase-merges" it) args))))
|
||||
(seq-some (##string-prefix-p "--rebase-merges" %) args))))
|
||||
(if (and commit (not confirm))
|
||||
(let ((process-environment process-environment))
|
||||
(when editor
|
||||
@@ -720,7 +726,7 @@ START has to be selected from a list of recent commits."
|
||||
;; merely to add new commits *after* it. Try not to
|
||||
;; ask users whether they really want to edit public
|
||||
;; commits, when they don't actually intend to do so.
|
||||
(not (--all-p (magit-rev-equal it commit) branches))))
|
||||
(not (seq-every-p (##magit-rev-equal % commit) branches))))
|
||||
(let ((m1 "Some of these commits have already been published to ")
|
||||
(m2 ".\nDo you really want to modify them"))
|
||||
(magit-confirm (or magit--rebase-published-symbol 'rebase-published)
|
||||
@@ -805,7 +811,7 @@ START has to be selected from a list of recent commits."
|
||||
(edit "edit")
|
||||
(remove "noop\n# pick")
|
||||
(reword "reword")
|
||||
(t (error "unknown action: %s" action)))
|
||||
(t (error "Unknown action: %s" action)))
|
||||
commit)))
|
||||
|
||||
;;;###autoload
|
||||
@@ -1013,7 +1019,7 @@ status buffer (i.e., the reverse of how they will be applied)."
|
||||
(propertize "merge" 'font-lock-face 'magit-sequence-pick)
|
||||
"\s"
|
||||
(magit-format-rev-summary hash) "\n"))
|
||||
(error "failed to parse merge message hash"))))))
|
||||
(error "Failed to parse merge message hash"))))))
|
||||
(let ((dir (magit-gitdir)))
|
||||
(magit-sequence-insert-sequence
|
||||
(magit-file-line (expand-file-name "rebase-merge/stopped-sha" dir))
|
||||
@@ -1025,9 +1031,9 @@ status buffer (i.e., the reverse of how they will be applied)."
|
||||
(defun magit-rebase-insert-apply-sequence (onto)
|
||||
(let* ((dir (magit-gitdir))
|
||||
(rewritten
|
||||
(--map (car (split-string it))
|
||||
(magit-file-lines
|
||||
(expand-file-name "rebase-apply/rewritten" dir))))
|
||||
(mapcar (##car (split-string %))
|
||||
(magit-file-lines
|
||||
(expand-file-name "rebase-apply/rewritten" dir))))
|
||||
(stop (magit-file-line
|
||||
(expand-file-name "rebase-apply/original-commit" dir))))
|
||||
(dolist (patch (nreverse (cdr (magit-rebase-patches))))
|
||||
@@ -1049,10 +1055,10 @@ status buffer (i.e., the reverse of how they will be applied)."
|
||||
(setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD")))
|
||||
(when (and stop (not (member (magit-rev-parse stop) done)))
|
||||
(let ((id (magit-patch-id stop)))
|
||||
(if-let ((matched (--first (equal (magit-patch-id it) id) done)))
|
||||
(if-let ((matched (seq-find (##equal (magit-patch-id %) id) done)))
|
||||
(setq stop matched)
|
||||
(cond
|
||||
((--first (magit-rev-equal it stop) done)
|
||||
((seq-find (##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...
|
||||
@@ -1078,7 +1084,7 @@ status buffer (i.e., the reverse of how they will be applied)."
|
||||
(t "work")))
|
||||
stop 'magit-sequence-part))
|
||||
;; The commit is definitely gone...
|
||||
((--first (magit-rev-equal it stop) done)
|
||||
((seq-find (##magit-rev-equal % stop) done)
|
||||
;; ...but all of its changes are still in effect.
|
||||
(magit-sequence-insert-commit "poof" stop 'magit-sequence-drop))
|
||||
(t
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-sparse-checkout.el --- Sparse checkout support for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Kyle Meyer <kyle@kyleam.com>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -43,13 +43,6 @@
|
||||
"Return non-nil if working tree is a sparse checkout."
|
||||
(magit-get-boolean "core.sparsecheckout"))
|
||||
|
||||
(defun magit-sparse-checkout--assert-version ()
|
||||
;; Older versions of Git have the ability to define sparse checkout
|
||||
;; patterns in .git/info/sparse-checkout, but the sparse-checkout
|
||||
;; command isn't available until 2.25.0.
|
||||
(when (magit-git-version< "2.25.0")
|
||||
(user-error "`git sparse-checkout' not available until Git v2.25")))
|
||||
|
||||
(defun magit-sparse-checkout--auto-enable ()
|
||||
(if (magit-sparse-checkout-enabled-p)
|
||||
(unless (magit-get-boolean "core.sparsecheckoutcone")
|
||||
@@ -89,7 +82,6 @@ See the `git sparse-checkout' manpage for details about
|
||||
(defun magit-sparse-checkout-enable (&optional args)
|
||||
"Convert the working tree to a sparse checkout."
|
||||
(interactive (list (transient-args 'magit-sparse-checkout)))
|
||||
(magit-sparse-checkout--assert-version)
|
||||
(magit-run-git-async "sparse-checkout" "init" "--cone" args))
|
||||
|
||||
;;;###autoload
|
||||
@@ -104,7 +96,6 @@ directories, call `magit-sparse-checkout-add' instead."
|
||||
;; dealing with very large trees, listing all subdirectories
|
||||
;; may need to be reconsidered.
|
||||
(magit-revision-directories "HEAD"))))
|
||||
(magit-sparse-checkout--assert-version)
|
||||
(magit-sparse-checkout--auto-enable)
|
||||
(magit-run-git-async "sparse-checkout" "set" directories))
|
||||
|
||||
@@ -124,7 +115,6 @@ directories, call `magit-sparse-checkout-set' instead."
|
||||
(regexp-opt (magit-sparse-checkout-directories)))))
|
||||
(lambda (d) (string-match-p re d)))
|
||||
(magit-revision-directories "HEAD")))))
|
||||
(magit-sparse-checkout--assert-version)
|
||||
(magit-sparse-checkout--auto-enable)
|
||||
(magit-run-git-async "sparse-checkout" "add" directories))
|
||||
|
||||
@@ -135,7 +125,6 @@ Some operations such as merging or rebasing may need to check out
|
||||
files that aren't included in the sparse checkout. Call this
|
||||
command to reset to the sparse checkout state."
|
||||
(interactive)
|
||||
(magit-sparse-checkout--assert-version)
|
||||
(magit-run-git-async "sparse-checkout" "reapply"))
|
||||
|
||||
;;;###autoload
|
||||
@@ -145,7 +134,6 @@ Note that disabling the sparse checkout does not clear the
|
||||
configured directories. Call `magit-sparse-checkout-enable' to
|
||||
restore the previous sparse checkout."
|
||||
(interactive)
|
||||
(magit-sparse-checkout--assert-version)
|
||||
(magit-run-git-async "sparse-checkout" "disable"))
|
||||
|
||||
;;; Miscellaneous
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-stash.el --- Stash support for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -39,10 +39,10 @@
|
||||
;;;; Diff options
|
||||
|
||||
(defcustom magit-stash-sections-hook
|
||||
'(magit-insert-stash-notes
|
||||
magit-insert-stash-worktree
|
||||
magit-insert-stash-index
|
||||
magit-insert-stash-untracked)
|
||||
(list #'magit-insert-stash-notes
|
||||
#'magit-insert-stash-worktree
|
||||
#'magit-insert-stash-index
|
||||
#'magit-insert-stash-untracked)
|
||||
"Hook run to insert sections into stash diff buffers."
|
||||
:package-version '(magit . "2.1.0")
|
||||
:group 'magit-stash
|
||||
@@ -129,8 +129,8 @@ while two prefix arguments are equivalent to `--all'."
|
||||
(interactive
|
||||
(progn (when (and (magit-merge-in-progress-p)
|
||||
(not (magit-y-or-n-p "\
|
||||
Stashing and resetting during a merge conflict. \
|
||||
Applying the resulting stash won't restore the merge state. \
|
||||
Stashing and resetting during a merge conflict. \
|
||||
Applying the resulting stash won't restore the merge state. \
|
||||
Proceed anyway? ")))
|
||||
(user-error "Abort"))
|
||||
(magit-stash-read-args)))
|
||||
@@ -143,7 +143,7 @@ Unstaged and untracked changes are not stashed. The stashed
|
||||
changes are applied in reverse to both the index and the
|
||||
worktree. This command can fail when the worktree is not clean.
|
||||
Applying the resulting stash has the inverse effect."
|
||||
(interactive (list (magit-stash-read-message)))
|
||||
(interactive (list (funcall magit-stash-read-message-function)))
|
||||
(magit-stash-save message t nil nil t 'worktree))
|
||||
|
||||
;;;###autoload
|
||||
@@ -256,27 +256,30 @@ specifying a list of files to be stashed."
|
||||
(list t)))
|
||||
(if transient
|
||||
(transient-setup 'magit-stash-push)
|
||||
(magit-run-git "stash" "push" args)))
|
||||
(magit-run-git "stash" "push"
|
||||
(seq-filter #'atom args)
|
||||
(assoc "--" args))))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-stash-apply (stash)
|
||||
"Apply a stash to the working tree.
|
||||
|
||||
First try \"git stash apply --index\", which tries to preserve
|
||||
the index stored in the stash, if any. This may fail because
|
||||
applying the stash could result in conflicts and those have to
|
||||
be stored in the index, making it impossible to also store the
|
||||
stash's index there as well.
|
||||
When using a Git release before v2.38.0, simply run \"git stash
|
||||
apply\" or with a prefix argument \"git stash apply --index\".
|
||||
|
||||
If the above failed, then try \"git stash apply\". This fails
|
||||
\(with or without \"--index\") if there are any uncommitted
|
||||
changes to files that are also modified in the stash.
|
||||
When using Git v2.38.0 or later, behave more intelligently:
|
||||
|
||||
If both of the above failed, then apply using \"git apply\".
|
||||
If there are no conflicting files, use \"--3way\". If there are
|
||||
conflicting files, then using \"--3way\" requires that those
|
||||
files are staged first, which may be undesirable, so prompt
|
||||
the user whether to use \"--3way\" or \"--reject\"."
|
||||
First try \"git stash apply --index\", which tries to preserve the
|
||||
index stored in the stash, if any. This may fail because applying
|
||||
the stash could result in conflicts and those have to be stored in
|
||||
the index, making it impossible to also store the stash's index
|
||||
there.
|
||||
|
||||
If \"git stash\" fails, then potentially fall back to using \"git
|
||||
apply\". If the stash does not touch any unstaged files, then pass
|
||||
\"--3way\" to that command. Otherwise ask the user whether to use
|
||||
that argument or \"--reject\". Customize `magit-no-confirm' if you
|
||||
want to fall back to using \"--3way\", without being prompted."
|
||||
(interactive (list (magit-read-stash "Apply stash")))
|
||||
(magit-stash--apply "apply" stash))
|
||||
|
||||
@@ -284,48 +287,82 @@ the user whether to use \"--3way\" or \"--reject\"."
|
||||
(defun magit-stash-pop (stash)
|
||||
"Apply a stash to the working tree, on success remove it from stash list.
|
||||
|
||||
First try \"git stash pop --index\", which tries to preserve
|
||||
the index stored in the stash, if any. This may fail because
|
||||
applying the stash could result in conflicts and those have to
|
||||
be stored in the index, making it impossible to also store the
|
||||
stash's index there as well.
|
||||
When using a Git release before v2.38.0, simply run \"git stash
|
||||
pop\" or with a prefix argument \"git stash pop --index\".
|
||||
|
||||
If the above failed, then try \"git stash apply\". This fails
|
||||
\(with or without \"--index\") if there are any uncommitted
|
||||
changes to files that are also modified in the stash.
|
||||
When using Git v2.38.0 or later, behave more intelligently:
|
||||
|
||||
If both of the above failed, then apply using \"git apply\".
|
||||
If there are no conflicting files, use \"--3way\". If there are
|
||||
conflicting files, then using \"--3way\" requires that those
|
||||
files are staged first, which may be undesirable, so prompt
|
||||
the user whether to use \"--3way\" or \"--reject\"."
|
||||
First try \"git stash apply --index\", which tries to preserve the
|
||||
index stored in the stash, if any. This may fail because applying
|
||||
the stash could result in conflicts and those have to be stored in
|
||||
the index, making it impossible to also store the stash's index
|
||||
there.
|
||||
|
||||
If \"git stash\" fails, then potentially fall back to using \"git
|
||||
apply\". If the stash does not touch any unstaged files, then pass
|
||||
\"--3way\" to that command. Otherwise ask the user whether to use
|
||||
that argument or \"--reject\". Customize `magit-no-confirm' if you
|
||||
want to fall back to using \"--3way\", without being prompted."
|
||||
(interactive (list (magit-read-stash "Pop stash")))
|
||||
(magit-stash--apply "pop" stash))
|
||||
|
||||
(defun magit-stash--apply (action stash)
|
||||
(or (= (magit-call-git "stash" action "--index" stash) 0)
|
||||
;; The stash's index could not be applied, so always keep the stash.
|
||||
(= (magit-call-git "stash" "apply" stash) 0)
|
||||
(let* ((range (format "%s^..%s" stash stash))
|
||||
(stashed (magit-git-items "diff" "-z" "--name-only" range "--"))
|
||||
(conflicts (cl-sort (cl-union (magit-unstaged-files t stashed)
|
||||
(magit-untracked-files t stashed)
|
||||
:test #'equal)
|
||||
#'string<))
|
||||
(arg (cond
|
||||
((not conflicts) "--3way")
|
||||
((magit-confirm-files
|
||||
'stash-apply-3way conflicts
|
||||
"Apply stash using `--3way', which requires first staging"
|
||||
"(else use `--reject')"
|
||||
t)
|
||||
(magit-stage-1 nil conflicts)
|
||||
"--3way")
|
||||
("--reject"))))
|
||||
(with-temp-buffer
|
||||
(magit-git-insert "diff" range)
|
||||
(magit-run-git-with-input "apply" arg "-"))))
|
||||
(magit-refresh))
|
||||
(if (magit-git-version< "2.38.0")
|
||||
(magit-run-git "stash" action stash (and current-prefix-arg "--index"))
|
||||
(magit-stash--apply-1 action stash)
|
||||
(magit-refresh)))
|
||||
|
||||
(defun magit-stash--apply-1 (action stash)
|
||||
(or
|
||||
(magit--run-git-stash action "--index" stash)
|
||||
;; The stash's index could not be applied, so always keep the stash.
|
||||
(magit--run-git-stash "apply" stash)
|
||||
(let* ((range (format "%s^..%s" stash stash))
|
||||
(stashed (magit-git-items "diff" "-z" "--name-only" range "--"))
|
||||
(conflicts (cl-sort (cl-union (magit-unstaged-files t stashed)
|
||||
(magit-untracked-files t stashed)
|
||||
:test #'equal)
|
||||
#'string<))
|
||||
(arg (if (or (not conflicts)
|
||||
(memq 'stash-apply-3way magit-no-confirm))
|
||||
"--3way"
|
||||
(magit-read-char-case
|
||||
(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")
|
||||
"\n")
|
||||
nil
|
||||
(?s (format
|
||||
"\n[s] stage file%s and apply with \"git apply --3way\""
|
||||
(if (length> conflicts 1) "s" ""))
|
||||
"--3way")
|
||||
(?r "\n[r] apply with \"git apply --reject\"" "--reject")
|
||||
(?c "\n[c] cancel" nil)))))
|
||||
(when arg
|
||||
(when (and (equal arg "--3way") conflicts)
|
||||
(magit-stage-1 nil conflicts))
|
||||
(with-temp-buffer
|
||||
(magit-git-insert "diff" range)
|
||||
(magit-run-git-with-input "apply" arg "-"))))))
|
||||
|
||||
(defun magit--run-git-stash (&rest args)
|
||||
(magit--with-temp-process-buffer
|
||||
(let ((exit (save-excursion
|
||||
(with-environment-variables (("LC_ALL" "en_US.utf8"))
|
||||
(magit-process-git t "stash" args))))
|
||||
(buffer (current-buffer))
|
||||
(failed (looking-at "\\`error: ")))
|
||||
(with-current-buffer (magit-process-buffer t)
|
||||
(magit-process-finish-section
|
||||
(magit-process-insert-section default-directory magit-git-executable
|
||||
(magit-process-git-arguments args)
|
||||
exit buffer)
|
||||
exit))
|
||||
(pcase (list exit failed)
|
||||
(`(0 ,_) t) ; no conflict
|
||||
(`(1 nil) t) ; successfully installed conflict
|
||||
(_ nil))))) ; could not install conflict, or genuine error
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-stash-drop (stash)
|
||||
@@ -348,7 +385,7 @@ When the region is active offer to drop all contained stashes."
|
||||
(defun magit-stash-clear (ref)
|
||||
"Remove all stashes saved in REF's reflog by deleting REF."
|
||||
(interactive (let ((ref (or (magit-section-value-if 'stashes) "refs/stash")))
|
||||
(magit-confirm t (format "Drop all stashes in %s" ref))
|
||||
(magit-confirm t (list "Drop all stashes in %s" ref))
|
||||
(list ref)))
|
||||
(magit-run-git "update-ref" "-d" ref))
|
||||
|
||||
@@ -375,7 +412,7 @@ Then apply STASH, dropping it if it applies cleanly."
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-stash-format-patch (stash)
|
||||
"Create a patch from STASH"
|
||||
"Create a patch from STASH."
|
||||
(interactive (list (magit-read-stash "Create patch from stash")))
|
||||
(with-temp-file (magit-rev-format "0001-%f.patch" stash)
|
||||
(magit-git-insert "stash" "show" "-p" stash))
|
||||
@@ -413,7 +450,7 @@ Then apply STASH, dropping it if it applies cleanly."
|
||||
(t "local"))))))
|
||||
|
||||
(defun magit-stash-store (message ref commit)
|
||||
(magit-update-ref ref message commit t))
|
||||
(magit-update-ref ref message commit))
|
||||
|
||||
(defun magit-stash-create (message index worktree untracked)
|
||||
(unless (magit-rev-parse "--verify" "HEAD")
|
||||
@@ -467,7 +504,7 @@ Then apply STASH, dropping it if it applies cleanly."
|
||||
"<1>" (magit-menu-item "Visit %v" #'magit-stash-show))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-stashes
|
||||
"Stashes" stashes "refs/stash")
|
||||
"Stashes" stashes "refs/stash" magit-insert-stashes)
|
||||
|
||||
(cl-defun magit-insert-stashes (&optional (ref "refs/stash")
|
||||
(heading "Stashes:"))
|
||||
@@ -511,8 +548,9 @@ instead of \"Stashes:\"."
|
||||
|
||||
(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes"
|
||||
"Mode for looking at lists of stashes."
|
||||
:interactive nil
|
||||
:group 'magit-log
|
||||
(hack-dir-local-variables-non-file-buffer))
|
||||
(magit-hack-dir-local-variables))
|
||||
|
||||
(defun magit-stashes-setup-buffer ()
|
||||
(magit-setup-buffer #'magit-stashes-mode nil
|
||||
@@ -520,9 +558,10 @@ instead of \"Stashes:\"."
|
||||
|
||||
(defun magit-stashes-refresh-buffer ()
|
||||
(magit-insert-section (stashesbuf)
|
||||
(magit-insert-heading (if (equal magit-buffer-refname "refs/stash")
|
||||
"Stashes:"
|
||||
(format "Stashes [%s]:" magit-buffer-refname)))
|
||||
(magit-insert-heading t
|
||||
(if (equal magit-buffer-refname "refs/stash")
|
||||
"Stashes"
|
||||
(format "Stashes [%s]" magit-buffer-refname)))
|
||||
(magit-git-wash (apply-partially #'magit-log-wash-log 'stash)
|
||||
"reflog" "--format=%gd%x00%aN%x00%at%x00%gs" magit-buffer-refname)))
|
||||
|
||||
@@ -571,10 +610,14 @@ If there is no stash buffer in the same frame, then do nothing."
|
||||
|
||||
(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash"
|
||||
"Mode for looking at individual stashes."
|
||||
:interactive nil
|
||||
:group 'magit-diff
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(magit-hack-dir-local-variables)
|
||||
(setq magit--imenu-group-types '(commit)))
|
||||
|
||||
(put 'magit-stash-mode 'magit-diff-default-arguments
|
||||
'("--no-ext-diff"))
|
||||
|
||||
(defun magit-stash-setup-buffer (stash args files)
|
||||
(magit-setup-buffer #'magit-stash-mode nil
|
||||
(magit-buffer-revision stash)
|
||||
@@ -607,13 +650,11 @@ If there is no stash buffer in the same frame, then do nothing."
|
||||
"Insert section showing notes for a stash.
|
||||
This shows the notes for stash@{N} but not for the other commits
|
||||
that make up the stash."
|
||||
(magit-insert-section section (note)
|
||||
(magit-insert-heading "Notes")
|
||||
(magit-insert-section (note)
|
||||
(magit-insert-heading t "Notes")
|
||||
(magit-git-insert "notes" "show" magit-buffer-revision)
|
||||
(if (= (point)
|
||||
(oref section content))
|
||||
(magit-cancel-section)
|
||||
(insert "\n"))))
|
||||
(magit-cancel-section 'if-empty)
|
||||
(insert "\n")))
|
||||
|
||||
(defun magit-insert-stash-index ()
|
||||
"Insert section showing staged changes of the stash."
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-status.el --- The grand overview -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
:type 'hook)
|
||||
|
||||
(defcustom magit-status-headers-hook
|
||||
'(magit-insert-error-header
|
||||
magit-insert-diff-filter-header
|
||||
magit-insert-head-branch-header
|
||||
magit-insert-upstream-branch-header
|
||||
magit-insert-push-branch-header
|
||||
magit-insert-tags-header)
|
||||
(list #'magit-insert-error-header
|
||||
#'magit-insert-diff-filter-header
|
||||
#'magit-insert-head-branch-header
|
||||
#'magit-insert-upstream-branch-header
|
||||
#'magit-insert-push-branch-header
|
||||
#'magit-insert-tags-header)
|
||||
"Hook run to insert headers into the status buffer.
|
||||
|
||||
This hook is run by `magit-insert-status-headers', which in turn
|
||||
@@ -55,32 +55,32 @@ all."
|
||||
:package-version '(magit . "2.1.0")
|
||||
:group 'magit-status
|
||||
:type 'hook
|
||||
:options '(magit-insert-error-header
|
||||
magit-insert-diff-filter-header
|
||||
magit-insert-repo-header
|
||||
magit-insert-remote-header
|
||||
magit-insert-head-branch-header
|
||||
magit-insert-upstream-branch-header
|
||||
magit-insert-push-branch-header
|
||||
magit-insert-tags-header))
|
||||
:options (list #'magit-insert-error-header
|
||||
#'magit-insert-diff-filter-header
|
||||
#'magit-insert-repo-header
|
||||
#'magit-insert-remote-header
|
||||
#'magit-insert-head-branch-header
|
||||
#'magit-insert-upstream-branch-header
|
||||
#'magit-insert-push-branch-header
|
||||
#'magit-insert-tags-header))
|
||||
|
||||
(defcustom magit-status-sections-hook
|
||||
'(magit-insert-status-headers
|
||||
magit-insert-merge-log
|
||||
magit-insert-rebase-sequence
|
||||
magit-insert-am-sequence
|
||||
magit-insert-sequencer-sequence
|
||||
magit-insert-bisect-output
|
||||
magit-insert-bisect-rest
|
||||
magit-insert-bisect-log
|
||||
magit-insert-untracked-files
|
||||
magit-insert-unstaged-changes
|
||||
magit-insert-staged-changes
|
||||
magit-insert-stashes
|
||||
magit-insert-unpushed-to-pushremote
|
||||
magit-insert-unpushed-to-upstream-or-recent
|
||||
magit-insert-unpulled-from-pushremote
|
||||
magit-insert-unpulled-from-upstream)
|
||||
(list #'magit-insert-status-headers
|
||||
#'magit-insert-merge-log
|
||||
#'magit-insert-rebase-sequence
|
||||
#'magit-insert-am-sequence
|
||||
#'magit-insert-sequencer-sequence
|
||||
#'magit-insert-bisect-output
|
||||
#'magit-insert-bisect-rest
|
||||
#'magit-insert-bisect-log
|
||||
#'magit-insert-untracked-files
|
||||
#'magit-insert-unstaged-changes
|
||||
#'magit-insert-staged-changes
|
||||
#'magit-insert-stashes
|
||||
#'magit-insert-unpushed-to-pushremote
|
||||
#'magit-insert-unpushed-to-upstream-or-recent
|
||||
#'magit-insert-unpulled-from-pushremote
|
||||
#'magit-insert-unpulled-from-upstream)
|
||||
"Hook run to insert sections into a status buffer."
|
||||
:package-version '(magit . "2.12.0")
|
||||
:group 'magit-status
|
||||
@@ -142,6 +142,49 @@ The functions which respect this option are
|
||||
:group 'magit-status
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom magit-status-show-untracked-files t
|
||||
"Whether to list untracked files in the status buffer.
|
||||
|
||||
- If nil, do not list any untracked files.
|
||||
- If t, list untracked files, but if a directory does not contain any
|
||||
untracked files, then only list that directory, not the contained
|
||||
untracked files.
|
||||
- If all, then list each individual untracked files. This is can be
|
||||
very slow and is discouraged.
|
||||
|
||||
The corresponding values for the Git variable are \"no\", \"normal\"
|
||||
and \"all\".
|
||||
|
||||
To disable listing untracked files in a specific repository only, add
|
||||
the following to \".dir-locals.el\":
|
||||
|
||||
((magit-status-mode
|
||||
(magit-status-show-untracked-files . \"no\")))
|
||||
|
||||
Alternatively (and mostly for historic reasons), it is possible to use
|
||||
`git-config' to set the repository-local value:
|
||||
|
||||
git config set --local status.showUntrackedFiles no
|
||||
|
||||
This does *not* override the (if any) local value of this Lisp variable,
|
||||
but it does override its global value.
|
||||
|
||||
See the last section in the git-status(1) manpage, to speed up the part
|
||||
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)
|
||||
|
||||
(defcustom magit-status-file-list-limit 100
|
||||
"How many files to list in file list sections in the status buffer.
|
||||
For performance reasons, it is recommended that you do not
|
||||
increase this limit."
|
||||
:package-version '(magit . "4.3.0")
|
||||
:group 'magit-status
|
||||
:type 'natnum)
|
||||
|
||||
(defcustom magit-status-margin
|
||||
(list nil
|
||||
(nth 1 magit-log-margin)
|
||||
@@ -342,38 +385,22 @@ init file: (global-set-key (kbd \"C-x g\") \\='magit-status-quick)."
|
||||
|
||||
(transient-define-prefix magit-status-jump ()
|
||||
"In a Magit-Status buffer, jump to a section."
|
||||
["Jump to"
|
||||
[("z " "Stashes" magit-jump-to-stashes
|
||||
:if (lambda () (memq 'magit-insert-stashes magit-status-sections-hook)))
|
||||
("t " "Tracked" magit-jump-to-tracked
|
||||
:if (lambda () (memq 'magit-insert-tracked-files magit-status-sections-hook)))
|
||||
("n " "Untracked" magit-jump-to-untracked
|
||||
:if (lambda () (memq 'magit-insert-untracked-files magit-status-sections-hook)))
|
||||
("u " "Unstaged" magit-jump-to-unstaged
|
||||
:if (lambda () (memq 'magit-insert-unstaged-changes magit-status-sections-hook)))
|
||||
("s " "Staged" magit-jump-to-staged
|
||||
:if (lambda () (memq 'magit-insert-staged-changes magit-status-sections-hook)))]
|
||||
[("fu" "Unpulled from upstream" magit-jump-to-unpulled-from-upstream
|
||||
:if (lambda () (memq 'magit-insert-unpulled-from-upstream magit-status-sections-hook)))
|
||||
("fp" "Unpulled from pushremote" magit-jump-to-unpulled-from-pushremote
|
||||
:if (lambda () (memq 'magit-insert-unpulled-from-pushremote magit-status-sections-hook)))
|
||||
("pu" magit-jump-to-unpushed-to-upstream
|
||||
:if (lambda ()
|
||||
(or (memq 'magit-insert-unpushed-to-upstream-or-recent magit-status-sections-hook)
|
||||
(memq 'magit-insert-unpushed-to-upstream magit-status-sections-hook)))
|
||||
:description (lambda ()
|
||||
(let ((upstream (magit-get-upstream-branch)))
|
||||
(if (or (not upstream)
|
||||
(magit-rev-ancestor-p "HEAD" upstream))
|
||||
"Recent commits"
|
||||
"Unmerged into upstream"))))
|
||||
("pp" "Unpushed to pushremote" magit-jump-to-unpushed-to-pushremote
|
||||
:if (lambda () (memq 'magit-insert-unpushed-to-pushremote magit-status-sections-hook)))
|
||||
("a " "Assumed unstaged" magit-jump-to-assume-unchanged
|
||||
:if (lambda () (memq 'magit-insert-assume-unchanged-files magit-status-sections-hook)))
|
||||
("w " "Skip worktree" magit-jump-to-skip-worktree
|
||||
:if (lambda () (memq 'magit-insert-skip-worktree-files magit-status-sections-hook)))]
|
||||
[("i" "Using Imenu" imenu)]])
|
||||
[["Jump to"
|
||||
("z " magit-jump-to-stashes)
|
||||
("t " magit-jump-to-tracked)
|
||||
("n " magit-jump-to-untracked)
|
||||
("i " magit-jump-to-ignored)
|
||||
("u " magit-jump-to-unstaged)
|
||||
("s " magit-jump-to-staged)]
|
||||
[""
|
||||
("fu" magit-jump-to-unpulled-from-upstream)
|
||||
("fp" magit-jump-to-unpulled-from-pushremote)
|
||||
("pu" magit-jump-to-unpushed-to-upstream)
|
||||
("pp" magit-jump-to-unpushed-to-pushremote)
|
||||
("a " magit-jump-to-assume-unchanged)
|
||||
("w " magit-jump-to-skip-worktree)]
|
||||
["Jump using"
|
||||
("j" "Imenu" imenu)]])
|
||||
|
||||
(define-derived-mode magit-status-mode magit-mode "Magit"
|
||||
"Mode for looking at Git status.
|
||||
@@ -401,10 +428,11 @@ Staging and applying changes is documented in info node
|
||||
Type \\[magit-commit] to create a commit.
|
||||
|
||||
\\{magit-status-mode-map}"
|
||||
:interactive nil
|
||||
:group 'magit-status
|
||||
(hack-dir-local-variables-non-file-buffer)
|
||||
(magit-hack-dir-local-variables)
|
||||
(when magit-status-initial-section
|
||||
(add-hook 'magit-refresh-buffer-hook
|
||||
(add-hook 'magit-post-create-buffer-hook
|
||||
#'magit-status-goto-initial-section nil t))
|
||||
(setq magit--imenu-group-types '(not branch commit)))
|
||||
|
||||
@@ -426,8 +454,8 @@ Type \\[magit-commit] to create a commit.
|
||||
magit-status-use-buffer-arguments))
|
||||
(file (and magit-status-goto-file-position
|
||||
(magit-file-relative-name)))
|
||||
(line (and file (line-number-at-pos)))
|
||||
(col (and file (current-column)))
|
||||
(line (and file (save-restriction (widen) (line-number-at-pos))))
|
||||
(col (and file (save-restriction (widen) (current-column))))
|
||||
(buf (magit-setup-buffer #'magit-status-mode nil
|
||||
(magit-buffer-diff-args (nth 0 d))
|
||||
(magit-buffer-diff-files (nth 1 d))
|
||||
@@ -454,20 +482,19 @@ Type \\[magit-commit] to create a commit.
|
||||
(defun magit-status-goto-initial-section ()
|
||||
"Jump to the section specified by `magit-status-initial-section'."
|
||||
(when-let ((section
|
||||
(--some (if (integerp it)
|
||||
(nth (1- it)
|
||||
(magit-section-siblings (magit-current-section)
|
||||
'next))
|
||||
(magit-get-section it))
|
||||
magit-status-initial-section)))
|
||||
(seq-some (lambda (initial)
|
||||
(if (integerp initial)
|
||||
(nth (1- initial)
|
||||
(magit-section-siblings
|
||||
(magit-current-section) 'next))
|
||||
(magit-get-section initial)))
|
||||
magit-status-initial-section)))
|
||||
(goto-char (oref section start))
|
||||
(when-let ((vis (cdr (assq 'magit-status-initial-section
|
||||
magit-section-initial-visibility-alist))))
|
||||
(if (eq vis 'hide)
|
||||
(magit-section-hide section)
|
||||
(magit-section-show section))))
|
||||
(remove-hook 'magit-refresh-buffer-hook
|
||||
#'magit-status-goto-initial-section t))
|
||||
(magit-section-show section)))))
|
||||
|
||||
(defun magit-status-maybe-update-revision-buffer (&optional _)
|
||||
"When moving in the status buffer, update the revision buffer.
|
||||
@@ -532,7 +559,7 @@ the status buffer causes this section to disappear again."
|
||||
(when magit-buffer-diff-files
|
||||
(insert " -- ")))
|
||||
(when magit-buffer-diff-files
|
||||
(insert (mapconcat #'identity magit-buffer-diff-files " ")))
|
||||
(insert (string-join magit-buffer-diff-files " ")))
|
||||
(insert ?\n))))
|
||||
|
||||
;;;; Reference Headers
|
||||
@@ -554,13 +581,13 @@ instead. The optional BRANCH argument is for internal use only."
|
||||
(insert (propertize commit 'font-lock-face 'magit-hash) ?\s))
|
||||
(insert (propertize branch 'font-lock-face 'magit-branch-local))
|
||||
(insert ?\s)
|
||||
(insert (funcall magit-log-format-message-function branch summary))
|
||||
(insert (magit-log--wash-summary summary))
|
||||
(insert ?\n))
|
||||
(magit-insert-section (commit commit)
|
||||
(insert (format "%-10s" "Head: "))
|
||||
(insert (propertize commit 'font-lock-face 'magit-hash))
|
||||
(insert ?\s)
|
||||
(insert (funcall magit-log-format-message-function nil summary))
|
||||
(insert (magit-log--wash-summary summary))
|
||||
(insert ?\n))))))
|
||||
|
||||
(defun magit-insert-upstream-branch-header (&optional branch upstream keyword)
|
||||
@@ -587,10 +614,9 @@ arguments are for internal use only."
|
||||
'font-lock-face 'magit-hash)
|
||||
" "))
|
||||
upstream " "
|
||||
(funcall magit-log-format-message-function upstream
|
||||
(funcall magit-log-format-message-function nil
|
||||
(or (magit-rev-format "%s" upstream)
|
||||
"(no commit message)"))))
|
||||
(magit-log--wash-summary
|
||||
(or (magit-rev-format "%s" upstream)
|
||||
"(no commit message)")))
|
||||
(cond
|
||||
((magit--unnamed-upstream-p remote merge)
|
||||
(concat (propertize merge 'font-lock-face 'magit-branch-remote)
|
||||
@@ -626,10 +652,8 @@ arguments are for internal use only."
|
||||
'font-lock-face 'magit-hash)
|
||||
" "))
|
||||
target " "
|
||||
(funcall magit-log-format-message-function target
|
||||
(funcall magit-log-format-message-function nil
|
||||
(or (magit-rev-format "%s" target)
|
||||
"(no commit message)"))))
|
||||
(magit-log--wash-summary (or (magit-rev-format "%s" target)
|
||||
"(no commit message)")))
|
||||
(let ((remote (magit-get-push-remote branch)))
|
||||
(if (magit-remote-p remote)
|
||||
(concat target " "
|
||||
@@ -706,116 +730,98 @@ remote in alphabetic order."
|
||||
"<2>" (magit-menu-item "Discard files" #'magit-discard)
|
||||
"<1>" (magit-menu-item "Stage files" #'magit-stage))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked)
|
||||
(magit-define-section-jumper magit-jump-to-untracked
|
||||
"Untracked files" untracked nil magit-insert-untracked-files)
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-tracked
|
||||
"Tracked files" tracked nil magit-insert-tracked-files)
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-ignored
|
||||
"Ignored files" ignored nil magit-insert-ignored-files)
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-skip-worktree
|
||||
"Skip-worktree files" skip-worktree nil magit-insert-skip-worktree-files)
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-assume-unchanged
|
||||
"Assume-unchanged files" assume-unchanged nil
|
||||
magit-insert-assume-unchanged-files)
|
||||
|
||||
(defun magit-insert-untracked-files ()
|
||||
"Maybe insert a list or tree of untracked files.
|
||||
"Maybe insert list of untracked files.
|
||||
|
||||
Do so depending on the value of `status.showUntrackedFiles'.
|
||||
Note that even if the value is `all', Magit still initially
|
||||
only shows directories. But the directory sections can then
|
||||
be expanded using \"TAB\".
|
||||
|
||||
If the first element of `magit-buffer-diff-files' is a
|
||||
directory, then limit the list to files below that. The value
|
||||
value of that variable can be set using \"D -- DIRECTORY RET g\"."
|
||||
(let* ((show (or (magit-get "status.showUntrackedFiles") "normal"))
|
||||
(base (car magit-buffer-diff-files))
|
||||
(base (and base (file-directory-p base) base)))
|
||||
(unless (equal show "no")
|
||||
(if (equal show "all")
|
||||
(when-let ((files (magit-untracked-files nil base)))
|
||||
(magit-insert-section (untracked)
|
||||
(magit-insert-heading "Untracked files:")
|
||||
(magit-insert-files files base)
|
||||
(insert ?\n)))
|
||||
(when-let ((files
|
||||
(--mapcat (and (eq (aref it 0) ??)
|
||||
(list (substring it 3)))
|
||||
(magit-git-items "status" "-z" "--porcelain"
|
||||
(magit-ignore-submodules-p t)
|
||||
"--" base))))
|
||||
(magit-insert-section (untracked)
|
||||
(magit-insert-heading "Untracked files:")
|
||||
(dolist (file files)
|
||||
(magit-insert-section (file file)
|
||||
(insert (propertize file 'font-lock-face 'magit-filename) ?\n)))
|
||||
(insert ?\n)))))))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked)
|
||||
List files if `magit-status-show-untracked-files' is non-nil, but also
|
||||
take the local value of Git variable `status.showUntrackedFiles' into
|
||||
account. The local value of the Lisp variable takes precedence over the
|
||||
local value of the Git variable. The global value of the Git variable
|
||||
is always ignored."
|
||||
(when-let*
|
||||
((value (or (and (local-variable-p 'magit-status-show-untracked-files)
|
||||
magit-status-show-untracked-files)
|
||||
(pcase (magit-get "--local" "status.showUntrackedFiles")
|
||||
((or "no" "off" "false" "0") 'no)
|
||||
((or "yes" "on" "true" "1") t)
|
||||
("all" 'all))
|
||||
magit-status-show-untracked-files))
|
||||
((not (eq value 'no))))
|
||||
(magit-insert-files
|
||||
'untracked
|
||||
(lambda (files)
|
||||
(mapcan (lambda (line)
|
||||
(and (eq (aref line 0) ??)
|
||||
(list (substring line 3))))
|
||||
(apply #'magit-git-items "status" "-z" "--porcelain"
|
||||
(format "--untracked-files=%s"
|
||||
(if (eq value 'all) "all" "normal"))
|
||||
"--" files))))))
|
||||
|
||||
(defun magit-insert-tracked-files ()
|
||||
"Insert a tree of tracked files.
|
||||
|
||||
If the first element of `magit-buffer-diff-files' is a
|
||||
directory, then limit the list to files below that. The value
|
||||
value of that variable can be set using \"D -- DIRECTORY RET g\"."
|
||||
(when-let ((files (magit-list-files)))
|
||||
(let* ((base (car magit-buffer-diff-files))
|
||||
(base (and base (file-directory-p base) base)))
|
||||
(magit-insert-section (tracked nil t)
|
||||
(magit-insert-heading "Tracked files:")
|
||||
(magit-insert-files files base)
|
||||
(insert ?\n)))))
|
||||
"Insert a list of tracked files.
|
||||
Honor the buffer's file filter, which can be set using \"D - -\"."
|
||||
(magit-insert-files 'tracked #'magit-list-files))
|
||||
|
||||
(defun magit-insert-ignored-files ()
|
||||
"Insert a tree of ignored files.
|
||||
|
||||
If the first element of `magit-buffer-diff-files' is a
|
||||
directory, then limit the list to files below that. The value
|
||||
of that variable can be set using \"D -- DIRECTORY RET g\"."
|
||||
(when-let ((files (magit-ignored-files)))
|
||||
(let* ((base (car magit-buffer-diff-files))
|
||||
(base (and base (file-directory-p base) base)))
|
||||
(magit-insert-section (tracked nil t)
|
||||
(magit-insert-heading "Ignored files:")
|
||||
(magit-insert-files files base)
|
||||
(insert ?\n)))))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-skip-worktree "Skip-worktree files" skip-worktree)
|
||||
"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))))
|
||||
|
||||
(defun magit-insert-skip-worktree-files ()
|
||||
"Insert a tree of skip-worktree files.
|
||||
|
||||
If the first element of `magit-buffer-diff-files' is a
|
||||
directory, then limit the list to files below that. The value
|
||||
of that variable can be set using \"D -- DIRECTORY RET g\"."
|
||||
(when-let ((files (magit-skip-worktree-files)))
|
||||
(let* ((base (car magit-buffer-diff-files))
|
||||
(base (and base (file-directory-p base) base)))
|
||||
(magit-insert-section (skip-worktree nil t)
|
||||
(magit-insert-heading "Skip-worktree files:")
|
||||
(magit-insert-files files base)
|
||||
(insert ?\n)))))
|
||||
|
||||
(magit-define-section-jumper magit-jump-to-assume-unchanged "Assume-unchanged files" assume-unchanged)
|
||||
"Insert a list of skip-worktree files.
|
||||
Honor the buffer's file filter, which can be set using \"D - -\"."
|
||||
(magit-insert-files 'skip-worktree #'magit-skip-worktree-files))
|
||||
|
||||
(defun magit-insert-assume-unchanged-files ()
|
||||
"Insert a tree of files that are assumed to be unchanged.
|
||||
"Insert a list of files that are assumed to be unchanged.
|
||||
Honor the buffer's file filter, which can be set using \"D - -\"."
|
||||
(magit-insert-files 'assume-unchanged #'magit-assume-unchanged-files))
|
||||
|
||||
If the first element of `magit-buffer-diff-files' is a
|
||||
directory, then limit the list to files below that. The value
|
||||
of that variable can be set using \"D -- DIRECTORY RET g\"."
|
||||
(when-let ((files (magit-assume-unchanged-files)))
|
||||
(let* ((base (car magit-buffer-diff-files))
|
||||
(base (and base (file-directory-p base) base)))
|
||||
(magit-insert-section (assume-unchanged nil t)
|
||||
(magit-insert-heading "Assume-unchanged files:")
|
||||
(magit-insert-files files base)
|
||||
(insert ?\n)))))
|
||||
|
||||
(defun magit-insert-files (files directory)
|
||||
(while (and files (string-prefix-p (or directory "") (car files)))
|
||||
(let ((dir (file-name-directory (car files))))
|
||||
(if (equal dir directory)
|
||||
(let ((file (pop files)))
|
||||
(magit-insert-section (file file)
|
||||
(insert (propertize file 'font-lock-face 'magit-filename) ?\n)))
|
||||
(magit-insert-section (file dir t)
|
||||
(insert (propertize dir 'file 'magit-filename) ?\n)
|
||||
(magit-insert-heading)
|
||||
(setq files (magit-insert-files files dir))))))
|
||||
files)
|
||||
(defun magit-insert-files (type fn)
|
||||
(when-let ((files (funcall fn
|
||||
(and magit-buffer-diff-files
|
||||
(cons "--" magit-buffer-diff-files)))))
|
||||
(magit-insert-section section ((eval type) nil t)
|
||||
(magit-insert-heading (length files)
|
||||
(let ((title (symbol-name type)))
|
||||
(format "%c%s files"
|
||||
(capitalize (aref title 0))
|
||||
(substring title 1))))
|
||||
(magit-insert-section-body
|
||||
(let ((magit-section-insert-in-reverse t)
|
||||
(limit magit-status-file-list-limit))
|
||||
(while (and files (> limit 0))
|
||||
(cl-decf limit)
|
||||
(let ((file (pop files)))
|
||||
(magit-insert-section (file file)
|
||||
(insert (funcall magit-format-file-function
|
||||
'list file 'magit-filename))
|
||||
(insert ?\n))))
|
||||
(when files
|
||||
(magit-insert-section (info)
|
||||
(insert (propertize
|
||||
(format "%s files not listed\n" (length files))
|
||||
'face 'warning)))))
|
||||
(insert ?\n)
|
||||
(oset section children (nreverse (oref section children)))))))
|
||||
|
||||
;;; _
|
||||
(provide 'magit-status)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-submodule.el --- Submodule support for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with Magit. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This library implements support for "git submodule".
|
||||
|
||||
;; See (info "(magit)Submodules").
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'magit)
|
||||
@@ -29,11 +35,11 @@
|
||||
;;; Options
|
||||
|
||||
(defcustom magit-module-sections-hook
|
||||
'(magit-insert-modules-overview
|
||||
magit-insert-modules-unpulled-from-upstream
|
||||
magit-insert-modules-unpulled-from-pushremote
|
||||
magit-insert-modules-unpushed-to-upstream
|
||||
magit-insert-modules-unpushed-to-pushremote)
|
||||
(list #'magit-insert-modules-overview
|
||||
#'magit-insert-modules-unpulled-from-upstream
|
||||
#'magit-insert-modules-unpulled-from-pushremote
|
||||
#'magit-insert-modules-unpushed-to-upstream
|
||||
#'magit-insert-modules-unpushed-to-pushremote)
|
||||
"Hook run by `magit-insert-modules'.
|
||||
|
||||
That function isn't part of `magit-status-sections-hook's default
|
||||
@@ -53,35 +59,37 @@ is inserted. If it is nil, then all sections listed in
|
||||
:group 'magit-status
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom magit-submodule-list-mode-hook '(hl-line-mode)
|
||||
(defcustom magit-submodule-list-mode-hook (list #'hl-line-mode)
|
||||
"Hook run after entering Magit-Submodule-List mode."
|
||||
:package-version '(magit . "2.9.0")
|
||||
:group 'magit-repolist
|
||||
:type 'hook
|
||||
:get 'magit-hook-custom-get
|
||||
:options '(hl-line-mode))
|
||||
:options (list #'hl-line-mode))
|
||||
|
||||
(defcustom magit-submodule-list-columns
|
||||
'(("Path" 25 magit-modulelist-column-path nil)
|
||||
("Version" 25 magit-repolist-column-version
|
||||
`(("Path" 25 ,#'magit-modulelist-column-path
|
||||
())
|
||||
("Version" 25 ,#'magit-repolist-column-version
|
||||
((:sort magit-repolist-version<)))
|
||||
("Branch" 20 magit-repolist-column-branch nil)
|
||||
("B<U" 3 magit-repolist-column-unpulled-from-upstream
|
||||
("Branch" 20 ,#'magit-repolist-column-branch
|
||||
())
|
||||
("B<P" 3 ,#'magit-repolist-column-unpulled-from-pushremote
|
||||
((:right-align t)
|
||||
(:sort <)))
|
||||
("B>U" 3 magit-repolist-column-unpushed-to-upstream
|
||||
("B<U" 3 ,#'magit-repolist-column-unpulled-from-upstream
|
||||
((:right-align t)
|
||||
(:sort <)))
|
||||
("B<P" 3 magit-repolist-column-unpulled-from-pushremote
|
||||
("B>P" 3 ,#'magit-repolist-column-unpushed-to-pushremote
|
||||
((:right-align t)
|
||||
(:sort <)))
|
||||
("B>P" 3 magit-repolist-column-unpushed-to-pushremote
|
||||
("B>U" 3 ,#'magit-repolist-column-unpushed-to-upstream
|
||||
((:right-align t)
|
||||
(:sort <)))
|
||||
("B" 3 magit-repolist-column-branches
|
||||
("S" 3 ,#'magit-repolist-column-stashes
|
||||
((:right-align t)
|
||||
(:sort <)))
|
||||
("S" 3 magit-repolist-column-stashes
|
||||
("B" 3 ,#'magit-repolist-column-branches
|
||||
((:right-align t)
|
||||
(:sort <))))
|
||||
"List of columns displayed by `magit-list-submodules'.
|
||||
@@ -177,8 +185,8 @@ and also setting this variable to t will lead to tears."
|
||||
("f" "Fetch modules" magit-fetch-modules)])
|
||||
|
||||
(defun magit-submodule-arguments (&rest filters)
|
||||
(--filter (and (member it filters) it)
|
||||
(transient-args 'magit-submodule)))
|
||||
(seq-filter (##and (member % filters) %)
|
||||
(transient-args 'magit-submodule)))
|
||||
|
||||
(defclass magit--git-submodule-suffix (transient-suffix)
|
||||
())
|
||||
@@ -246,8 +254,7 @@ it is nil, then PATH also becomes the name."
|
||||
(magit-process-sentinel process event)
|
||||
(process-put process 'inhibit-refresh t)
|
||||
(magit-process-sentinel process event)
|
||||
(when (magit-git-version>= "2.12.0")
|
||||
(magit-call-git "submodule" "absorbgitdirs" path))
|
||||
(magit-call-git "submodule" "absorbgitdirs" path)
|
||||
(magit-refresh)))))))
|
||||
|
||||
;;;###autoload
|
||||
@@ -257,10 +264,10 @@ it is nil, then PATH also becomes the name."
|
||||
(push (if prefer-short path name) minibuffer-history)
|
||||
(magit-read-string-ns
|
||||
"Submodule name" nil (cons 'minibuffer-history 2)
|
||||
(or (--keep (pcase-let ((`(,var ,val) (split-string it "=")))
|
||||
(and (equal val path)
|
||||
(cadr (split-string var "\\."))))
|
||||
(magit-git-lines "config" "--list" "-f" ".gitmodules"))
|
||||
(or (seq-keep (##pcase-let ((`(,var ,val) (split-string % "=")))
|
||||
(and (equal val path)
|
||||
(cadr (split-string var "\\."))))
|
||||
(magit-git-lines "config" "--list" "-f" ".gitmodules"))
|
||||
(if prefer-short name path)))))
|
||||
|
||||
;;;###autoload (autoload 'magit-submodule-register "magit-submodule" nil t)
|
||||
@@ -283,7 +290,7 @@ single module from the user."
|
||||
(magit-run-git-async "submodule" "init" "--" modules)))
|
||||
|
||||
;;;###autoload (autoload 'magit-submodule-populate "magit-submodule" nil t)
|
||||
(transient-define-suffix magit-submodule-populate (modules)
|
||||
(transient-define-suffix magit-submodule-populate (modules args)
|
||||
"Create MODULES working directories, checking out the recorded commits.
|
||||
|
||||
With a prefix argument act on all suitable modules. Otherwise,
|
||||
@@ -293,11 +300,13 @@ single module from the user."
|
||||
;; This is the command that actually "initializes" modules.
|
||||
;; A module is initialized when it has a working directory,
|
||||
;; a gitlink, and a .gitmodules entry.
|
||||
:description "Populate git submodule update --init"
|
||||
:class 'magit--git-submodule-suffix
|
||||
:description "Populate git submodule update --init [--recursive]"
|
||||
(interactive
|
||||
(list (magit-module-confirm "Populate" 'magit-module-no-worktree-p)))
|
||||
(list (magit-module-confirm "Populate" 'magit-module-no-worktree-p)
|
||||
(magit-submodule-arguments "--recursive")))
|
||||
(magit-with-toplevel
|
||||
(magit-run-git-async "submodule" "update" "--init" "--" modules)))
|
||||
(magit-run-git-async "submodule" "update" "--init" args "--" modules)))
|
||||
|
||||
;;;###autoload (autoload 'magit-submodule-update "magit-submodule" nil t)
|
||||
(transient-define-suffix magit-submodule-update (modules args)
|
||||
@@ -346,8 +355,8 @@ With a prefix argument act on all suitable modules. Otherwise,
|
||||
if the region selects modules, then act on those. Otherwise, if
|
||||
there is a module at point, then act on that. Otherwise read a
|
||||
single module from the user."
|
||||
;; Even though a package is "uninitialized" (it has no worktree)
|
||||
;; the super-projects $GIT_DIR/config may never-the-less set the
|
||||
;; Even when a submodule is "uninitialized" (it has no worktree)
|
||||
;; the super-project's $GIT_DIR/config may never-the-less set the
|
||||
;; module's url. This may happen if you `deinit' and then `init'
|
||||
;; to register (NOT initialize). Because the purpose of `deinit'
|
||||
;; is to remove the working directory AND to remove the url, this
|
||||
@@ -381,8 +390,6 @@ to recover from making a mistake here, but don't count on it."
|
||||
(list (magit-read-module-path "Remove module")))
|
||||
(magit-submodule-arguments "--force")
|
||||
current-prefix-arg))
|
||||
(when (magit-git-version< "2.12.0")
|
||||
(error "This command requires Git v2.12.0"))
|
||||
(when magit-submodule-remove-trash-gitdirs
|
||||
(setq trash-gitdirs t))
|
||||
(magit-with-toplevel
|
||||
@@ -408,16 +415,16 @@ to recover from making a mistake here, but don't count on it."
|
||||
(if (cdr modified)
|
||||
(message "Omitting %s modules with uncommitted changes: %s"
|
||||
(length modified)
|
||||
(mapconcat #'identity modified ", "))
|
||||
(string-join modified ", "))
|
||||
(message "Omitting module %s, it has uncommitted changes"
|
||||
(car modified)))
|
||||
(setq modules (cl-set-difference modules modified :test #'equal))))
|
||||
(when modules
|
||||
(let ((alist
|
||||
(and trash-gitdirs
|
||||
(--map (split-string it "\0")
|
||||
(magit-git-lines "submodule" "foreach" "-q"
|
||||
"printf \"$sm_path\\0$name\n\"")))))
|
||||
(mapcar (##split-string % "\0")
|
||||
(magit-git-lines "submodule" "foreach" "-q"
|
||||
"printf \"$sm_path\\0$name\n\"")))))
|
||||
(magit-git "submodule" "absorbgitdirs" "--" modules)
|
||||
(magit-git "submodule" "deinit" args "--" modules)
|
||||
(magit-git "rm" args "--" modules)
|
||||
@@ -488,7 +495,7 @@ or, failing that, the abbreviated HEAD commit hash."
|
||||
(dolist (module modules)
|
||||
(let ((default-directory
|
||||
(expand-file-name (file-name-as-directory module))))
|
||||
(magit-insert-section (magit-module-section module t)
|
||||
(magit-insert-section (module module t)
|
||||
(insert (propertize (format path-format module)
|
||||
'font-lock-face 'magit-diff-file-heading))
|
||||
(if (not (file-exists-p ".git"))
|
||||
@@ -588,39 +595,38 @@ These sections can be expanded to show the respective commits."
|
||||
|
||||
(defun magit--insert-modules-logs (heading type range)
|
||||
"For internal use, don't add to a hook."
|
||||
(unless (magit-ignore-submodules-p)
|
||||
(when-let ((modules (magit-list-module-paths)))
|
||||
(magit-insert-section section ((eval type) nil t)
|
||||
(string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading)
|
||||
(magit-insert-heading
|
||||
(propertize (match-string 1 heading)
|
||||
'font-lock-face 'magit-section-heading)
|
||||
" "
|
||||
(propertize (match-string 2 heading)
|
||||
'font-lock-face 'magit-branch-remote)
|
||||
":")
|
||||
(magit-with-toplevel
|
||||
(dolist (module modules)
|
||||
(when (magit-module-worktree-p module)
|
||||
(let ((default-directory
|
||||
(expand-file-name (file-name-as-directory module))))
|
||||
(when (magit-file-accessible-directory-p default-directory)
|
||||
(magit-insert-section sec (magit-module-section module t)
|
||||
(magit-insert-heading
|
||||
(propertize module
|
||||
'font-lock-face 'magit-diff-file-heading)
|
||||
":")
|
||||
(oset sec range range)
|
||||
(magit-git-wash
|
||||
(apply-partially #'magit-log-wash-log 'module)
|
||||
"-c" "push.default=current" "log" "--oneline" range)
|
||||
(when (> (point)
|
||||
(oref sec content))
|
||||
(delete-char -1))))))))
|
||||
(if (> (point)
|
||||
(oref section content))
|
||||
(insert ?\n)
|
||||
(magit-cancel-section))))))
|
||||
(when-let (((not (magit-ignore-submodules-p)))
|
||||
(modules (magit-list-module-paths)))
|
||||
(magit-insert-section ((eval type) nil t)
|
||||
(string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading)
|
||||
(magit-insert-heading
|
||||
(propertize (match-string 1 heading)
|
||||
'font-lock-face 'magit-section-heading)
|
||||
" "
|
||||
(propertize (match-string 2 heading)
|
||||
'font-lock-face 'magit-branch-remote)
|
||||
":")
|
||||
(dolist (module modules)
|
||||
(when-let* ((default-directory (expand-file-name module))
|
||||
((file-exists-p (expand-file-name ".git")))
|
||||
(lines (magit-git-lines "-c" "push.default=current"
|
||||
"log" "--oneline" range))
|
||||
(count (length lines))
|
||||
((> count 0)))
|
||||
(magit-insert-section
|
||||
( module module t
|
||||
:range range)
|
||||
(magit-insert-heading count
|
||||
(propertize module 'font-lock-face 'magit-diff-file-heading))
|
||||
(dolist (line lines)
|
||||
(string-match magit-log-module-re line)
|
||||
(let ((rev (match-string 1 line))
|
||||
(msg (match-string 2 line)))
|
||||
(magit-insert-section (module-commit rev t)
|
||||
(insert (propertize rev 'font-lock-face 'magit-hash) " "
|
||||
(magit-log--wash-summary msg) "\n")))))))
|
||||
(magit-cancel-section 'if-empty)
|
||||
(insert ?\n))))
|
||||
|
||||
;;; List
|
||||
|
||||
@@ -634,15 +640,12 @@ These sections can be expanded to show the respective commits."
|
||||
:doc "Local keymap for Magit-Submodule-List mode buffers."
|
||||
:parent magit-repolist-mode-map)
|
||||
|
||||
(define-derived-mode magit-submodule-list-mode tabulated-list-mode "Modules"
|
||||
(define-derived-mode magit-submodule-list-mode magit-repolist-mode "Modules"
|
||||
"Major mode for browsing a list of Git submodules."
|
||||
:group 'magit-repolist-mode
|
||||
(setq-local x-stretch-cursor nil)
|
||||
(setq tabulated-list-padding 0)
|
||||
(add-hook 'tabulated-list-revert-hook #'magit-submodule-list-refresh nil t)
|
||||
(setq imenu-prev-index-position-function
|
||||
#'magit-repolist--imenu-prev-index-position)
|
||||
(setq imenu-extract-index-name-function #'tabulated-list-get-id))
|
||||
:interactive nil
|
||||
:group 'magit-repolist
|
||||
(setq-local tabulated-list-revert-hook
|
||||
(list #'magit-submodule-list-refresh t)))
|
||||
|
||||
(defvar-local magit-submodule-list-predicate nil)
|
||||
|
||||
@@ -666,7 +669,7 @@ These sections can be expanded to show the respective commits."
|
||||
(and (file-exists-p ".git")
|
||||
(or (not magit-submodule-list-predicate)
|
||||
(funcall magit-submodule-list-predicate module))
|
||||
(list module
|
||||
(list default-directory
|
||||
(vconcat
|
||||
(mapcar (pcase-lambda (`(,title ,width ,fn ,props))
|
||||
(or (funcall fn `((:path ,module)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-subtree.el --- Subtree support for Magit -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with Magit. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This library implements support for "git subtree".
|
||||
;; The entry point is the `magit-subtree' menu command.
|
||||
|
||||
;; See (info "(magit)Subtree").
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'magit)
|
||||
@@ -30,7 +37,7 @@
|
||||
(transient-define-prefix magit-subtree ()
|
||||
"Import or export subtrees."
|
||||
:man-page "git-subtree"
|
||||
["Actions"
|
||||
["Subtree actions"
|
||||
("i" "Import" magit-subtree-import)
|
||||
("e" "Export" magit-subtree-export)])
|
||||
|
||||
@@ -42,7 +49,7 @@
|
||||
(magit-subtree:--prefix)
|
||||
(magit-subtree:--message)
|
||||
("-s" "Squash" "--squash")]
|
||||
["Actions"
|
||||
["Subtree import actions"
|
||||
[("a" "Add" magit-subtree-add)
|
||||
("c" "Add commit" magit-subtree-add-commit)]
|
||||
[("m" "Merge" magit-subtree-merge)
|
||||
@@ -59,7 +66,7 @@
|
||||
(magit-subtree:--onto)
|
||||
("-i" "Ignore joins" "--ignore-joins")
|
||||
("-j" "Rejoin" "--rejoin")]
|
||||
["Actions"
|
||||
["Subtree export actions"
|
||||
("p" "Push" magit-subtree-push)
|
||||
("s" "Split" magit-subtree-split)])
|
||||
|
||||
@@ -107,14 +114,14 @@
|
||||
:reader #'magit-transient-read-revision)
|
||||
|
||||
(defun magit-subtree-prefix (transient prompt)
|
||||
(if-let ((arg (--first (string-prefix-p "--prefix=" it)
|
||||
(transient-args transient))))
|
||||
(if-let ((arg (seq-find (##string-prefix-p "--prefix=" %)
|
||||
(transient-args transient))))
|
||||
(substring arg 9)
|
||||
(magit-subtree-read-prefix prompt)))
|
||||
|
||||
(defun magit-subtree-arguments (transient)
|
||||
(--remove (string-prefix-p "--prefix=" it)
|
||||
(transient-args transient)))
|
||||
(seq-remove (##string-prefix-p "--prefix=" %)
|
||||
(transient-args transient)))
|
||||
|
||||
(defun magit-git-subtree (subcmd prefix &rest args)
|
||||
(magit-run-git-async "subtree" subcmd (concat "--prefix=" prefix) args))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-tag.el --- Tag functionality -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -38,9 +38,10 @@
|
||||
"Create or delete a tag."
|
||||
:man-page "git-tag"
|
||||
["Arguments"
|
||||
("-f" "Force" ("-f" "--force"))
|
||||
("-a" "Annotate" ("-a" "--annotate"))
|
||||
("-s" "Sign" ("-s" "--sign"))
|
||||
("-f" "Force" ("-f" "--force"))
|
||||
("-e" "Edit message" ("-e" "--edit"))
|
||||
("-a" "Annotate" ("-a" "--annotate"))
|
||||
("-s" "Sign" ("-s" "--sign"))
|
||||
(magit-tag:--local-user)]
|
||||
[["Create"
|
||||
("t" "tag" magit-tag-create)
|
||||
@@ -113,7 +114,7 @@ defaulting to the tag at point.
|
||||
(when tags
|
||||
(magit-call-git "tag" "-d" tags))
|
||||
(when remote-tags
|
||||
(magit-run-git-async "push" remote (--map (concat ":" it) remote-tags))))
|
||||
(magit-run-git-async "push" remote (mapcar (##concat ":" %) remote-tags))))
|
||||
|
||||
(defvar magit-tag-version-regexp-alist
|
||||
'(("^[-._+ ]?snapshot\\.?$" . -4)
|
||||
@@ -155,17 +156,15 @@ prompt for the name of the new tag using the highest existing
|
||||
tag as initial input and leaving it to the user to increment the
|
||||
desired part of the version string.
|
||||
|
||||
If `--annotate' is enabled, then prompt for the message of the
|
||||
new tag. Base the proposed tag message on the message of the
|
||||
highest tag, provided that that contains the corresponding
|
||||
version string and substituting the new version string for that.
|
||||
Otherwise propose something like \"Foo-Bar 1.2.3\", given, for
|
||||
example, a TAG \"v1.2.3\" and a repository located at something
|
||||
like \"/path/to/foo-bar\"."
|
||||
When creating an annotated tag, prepare a message based on the message
|
||||
of the highest existing tag, provided that contains the corresponding
|
||||
version string, and substituting the new version string for that. If
|
||||
that is not the case, propose a message using a reasonable format."
|
||||
(interactive
|
||||
(save-match-data
|
||||
(pcase-let*
|
||||
((`(,pver ,ptag ,pmsg) (car (magit--list-releases)))
|
||||
((args (magit-tag-arguments))
|
||||
(`(,pver ,ptag ,pmsg) (car (magit--list-releases)))
|
||||
(msg (magit-rev-format "%s"))
|
||||
(ver (and (string-match magit-release-commit-regexp msg)
|
||||
(match-string 1 msg)))
|
||||
@@ -176,6 +175,10 @@ like \"/path/to/foo-bar\"."
|
||||
(user-error "Use `sisyphus-create-release' first")))
|
||||
(tag (cond
|
||||
((not ptag)
|
||||
;; Force the user to review the message used for the
|
||||
;; initial release tag, in case they do not like the
|
||||
;; default format.
|
||||
(cl-pushnew "--edit" args :test #'equal)
|
||||
(read-string "Create first release tag: "
|
||||
(if (and ver (string-match-p "\\`[0-9]" ver))
|
||||
(concat "v" ver)
|
||||
@@ -189,23 +192,23 @@ like \"/path/to/foo-bar\"."
|
||||
(format "Create release tag (previous was %s): " ptag)
|
||||
ptag))))
|
||||
(ver (and (string-match magit-release-tag-regexp tag)
|
||||
(match-string 2 tag)))
|
||||
(args (magit-tag-arguments)))
|
||||
(match-string 2 tag))))
|
||||
(list tag
|
||||
(and (member "--annotate" args)
|
||||
(read-string
|
||||
(format "Message for %S: " tag)
|
||||
(cond ((and pver (string-match (regexp-quote pver) pmsg))
|
||||
(replace-match ver t t pmsg))
|
||||
((and ptag (string-match (regexp-quote ptag) pmsg))
|
||||
(replace-match tag t t pmsg))
|
||||
(t (format "%s %s"
|
||||
(capitalize
|
||||
(file-name-nondirectory
|
||||
(directory-file-name (magit-toplevel))))
|
||||
ver)))))
|
||||
(and (seq-some (apply-partially
|
||||
#'string-match-p
|
||||
"\\`--\\(annotate\\|local-user\\|sign\\)")
|
||||
args)
|
||||
(cond ((and pver (string-match (regexp-quote pver) pmsg))
|
||||
(replace-match ver t t pmsg))
|
||||
((and ptag (string-match (regexp-quote ptag) pmsg))
|
||||
(replace-match tag t t pmsg))
|
||||
((format "%s %s"
|
||||
(capitalize
|
||||
(file-name-nondirectory
|
||||
(directory-file-name (magit-toplevel))))
|
||||
ver))))
|
||||
args))))
|
||||
(magit-run-git-async "tag" args (and msg (list "-m" msg)) tag)
|
||||
(magit-run-git-with-editor "tag" args (and msg (list "-m" msg)) tag)
|
||||
(set-process-sentinel
|
||||
magit-this-process
|
||||
(lambda (process event)
|
||||
@@ -223,7 +226,7 @@ a tag qualifies as a release tag."
|
||||
(mapcar
|
||||
#'cdr
|
||||
(nreverse
|
||||
(cl-sort (cl-mapcan
|
||||
(cl-sort (mapcan
|
||||
(lambda (line)
|
||||
(and (string-match " +" line)
|
||||
(let ((tag (substring line 0 (match-beginning 0)))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-transient.el --- Support for transients -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;;; magit-version.el --- the Magit version you are using
|
||||
|
||||
(setq magit-version "3.3.0")
|
||||
(setq magit-version "4.3.0")
|
||||
|
||||
(provide 'migit-version)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-wip.el --- Commit snapshots to work-in-progress refs -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -158,14 +158,13 @@ variant `magit-wip-after-save-mode'."
|
||||
(let (files)
|
||||
(if-let ((elt (assoc top magit--wip-activation-cache)))
|
||||
(setq files (cddr elt))
|
||||
(progn
|
||||
(setq files (let ((default-directory top))
|
||||
(magit-tracked-files)))
|
||||
(push `(,top ,top ,@files)
|
||||
magit--wip-activation-cache)
|
||||
(unless (eq default-directory top)
|
||||
(push `(,default-directory ,top ,@files)
|
||||
magit--wip-activation-cache))))
|
||||
(setq files (let ((default-directory top))
|
||||
(magit-tracked-files)))
|
||||
(push `(,top ,top ,@files)
|
||||
magit--wip-activation-cache)
|
||||
(unless (eq default-directory top)
|
||||
(push `(,default-directory ,top ,@files)
|
||||
magit--wip-activation-cache)))
|
||||
(member (file-relative-name buffer-file-name) files))
|
||||
(push (list default-directory nil)
|
||||
magit--wip-activation-cache)
|
||||
@@ -186,13 +185,13 @@ variant `magit-wip-after-save-mode'."
|
||||
Also see `magit-wip-after-save-mode' which calls this function
|
||||
automatically whenever a buffer visiting a tracked file is saved."
|
||||
(interactive (list "wip-save %s after save"))
|
||||
(unless magit--wip-inhibit-autosave
|
||||
(when-let ((ref (magit-wip-get-ref)))
|
||||
(magit-with-toplevel
|
||||
(let ((file (file-relative-name buffer-file-name)))
|
||||
(magit-wip-commit-worktree
|
||||
ref (list file)
|
||||
(format (or msg "autosave %s after save") file)))))))
|
||||
(when-let (((not magit--wip-inhibit-autosave))
|
||||
(ref (magit-wip-get-ref)))
|
||||
(magit-with-toplevel
|
||||
(let ((file (file-relative-name buffer-file-name)))
|
||||
(magit-wip-commit-worktree
|
||||
ref (list file)
|
||||
(format (or msg "autosave %s after save") file))))))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode magit-wip-after-apply-mode
|
||||
@@ -318,11 +317,9 @@ commit message."
|
||||
;; Note: `update-index' is used instead of `add'
|
||||
;; because `add' will fail if a file is already
|
||||
;; deleted in the temporary index.
|
||||
(magit-call-git
|
||||
"update-index" "--add" "--remove"
|
||||
(and (magit-git-version>= "2.25.0")
|
||||
"--ignore-skip-worktree-entries")
|
||||
"--" files)
|
||||
(magit-call-git "update-index" "--add" "--remove"
|
||||
"--ignore-skip-worktree-entries"
|
||||
"--" files)
|
||||
(magit-with-toplevel
|
||||
(magit-call-git "add" "-u" ".")))
|
||||
(magit-git-string "write-tree"))))
|
||||
@@ -359,9 +356,9 @@ commit message."
|
||||
(setq msg (concat
|
||||
(cond ((= len 0) "autosave tracked files")
|
||||
((> len 1) (format "autosave %s files" len))
|
||||
(t (concat "autosave "
|
||||
(file-relative-name (car files)
|
||||
(magit-toplevel)))))
|
||||
((concat "autosave "
|
||||
(file-relative-name (car files)
|
||||
(magit-toplevel)))))
|
||||
msg))))
|
||||
(magit-update-ref wipref msg
|
||||
(magit-git-string "commit-tree" "--no-gpg-sign"
|
||||
@@ -461,7 +458,7 @@ many \"branches\" of each wip ref are shown."
|
||||
(while (and reflog (> count 1))
|
||||
;; "start autosaving ..." is the current message, but it used
|
||||
;; to be "restart autosaving ...", and those messages may
|
||||
;; still be around (e.g., if gc.reflogExpire is to "never").
|
||||
;; still be around (e.g., if gc.reflogExpire is set to "never").
|
||||
(setq reflog (cl-member "^[^ ]+ [^:]+: \\(?:re\\)?start autosaving"
|
||||
reflog :test #'string-match-p))
|
||||
(when (and (cadr reflog)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
;;; magit-worktree.el --- Worktree support -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -61,20 +61,20 @@ Used by `magit-worktree-checkout' and `magit-worktree-branch'."
|
||||
(list (funcall magit-worktree-read-directory-name-function
|
||||
(format "Checkout %s in new worktree: " branch))
|
||||
branch)))
|
||||
(magit-run-git "worktree" "add" (magit--expand-worktree path) branch)
|
||||
(magit-diff-visit-directory path))
|
||||
(when (zerop (magit-run-git "worktree" "add"
|
||||
(magit--expand-worktree path) branch))
|
||||
(magit-diff-visit-directory path)))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-worktree-branch (path branch start-point &optional force)
|
||||
(defun magit-worktree-branch (path branch start-point)
|
||||
"Create a new BRANCH and check it out in a new worktree at PATH."
|
||||
(interactive
|
||||
`(,(funcall magit-worktree-read-directory-name-function
|
||||
"Create worktree: ")
|
||||
,@(magit-branch-read-args "Create and checkout branch")
|
||||
,current-prefix-arg))
|
||||
(magit-run-git "worktree" "add" (if force "-B" "-b")
|
||||
branch (magit--expand-worktree path) start-point)
|
||||
(magit-diff-visit-directory path))
|
||||
,@(magit-branch-read-args "Create and checkout branch")))
|
||||
(when (zerop (magit-run-git "worktree" "add" "-b" branch
|
||||
(magit--expand-worktree path) start-point))
|
||||
(magit-diff-visit-directory path)))
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-worktree-move (worktree path)
|
||||
@@ -113,7 +113,7 @@ The primary worktree cannot be deleted."
|
||||
(user-error "Deleting %s would delete the shared .git directory" worktree)
|
||||
(let ((primary (file-name-as-directory (caar (magit-list-worktrees)))))
|
||||
(magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete)
|
||||
(list "worktree"))
|
||||
(list worktree))
|
||||
(when (file-exists-p worktree)
|
||||
(let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
|
||||
(delete-directory worktree t magit-delete-by-moving-to-trash)))
|
||||
@@ -160,7 +160,7 @@ If there is only one worktree, then insert nothing."
|
||||
(let ((worktrees (magit-list-worktrees)))
|
||||
(when (length> worktrees 1)
|
||||
(magit-insert-section (worktrees)
|
||||
(magit-insert-heading "Worktrees:")
|
||||
(magit-insert-heading t "Worktrees")
|
||||
(let* ((cols
|
||||
(mapcar
|
||||
(lambda (config)
|
||||
@@ -178,7 +178,7 @@ If there is only one worktree, then insert nothing."
|
||||
(bare "(bare)"))
|
||||
config)))
|
||||
worktrees))
|
||||
(align (1+ (apply #'max (--map (string-width (car it)) cols)))))
|
||||
(align (1+ (apply #'max (mapcar (##string-width (car %)) cols)))))
|
||||
(pcase-dolist (`(,head . ,config) cols)
|
||||
(magit--insert-worktree
|
||||
config
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding:t; coding:utf-8 -*-
|
||||
|
||||
;; Copyright (C) 2008-2023 The Magit Project Contributors
|
||||
;; Copyright (C) 2008-2025 The Magit Project Contributors
|
||||
|
||||
;; Author: Marius Vollmer <marius.vollmer@gmail.com>
|
||||
;; Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
|
||||
;; Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
|
||||
;; Kyle Meyer <kyle@kyleam.com>
|
||||
;; Former-Maintainers:
|
||||
;; Nicolas Dudebout <nicolas.dudebout@gatech.edu>
|
||||
@@ -17,16 +17,15 @@
|
||||
;; Homepage: https://github.com/magit/magit
|
||||
;; Keywords: git tools vc
|
||||
|
||||
;; Package-Version: 3.3.0.50-git
|
||||
;; Package-Version: 4.3.0
|
||||
;; Package-Requires: (
|
||||
;; (emacs "25.1")
|
||||
;; (compat "29.1.3.4")
|
||||
;; (dash "2.19.1")
|
||||
;; (git-commit "3.3.0")
|
||||
;; (magit-section "3.3.0")
|
||||
;; (emacs "27.1")
|
||||
;; (compat "30.0.2.0")
|
||||
;; (llama "0.6.0")
|
||||
;; (magit-section "4.3.0")
|
||||
;; (seq "2.24")
|
||||
;; (transient "0.3.6")
|
||||
;; (with-editor "3.0.5"))
|
||||
;; (transient "0.8.4")
|
||||
;; (with-editor "3.4.3"))
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -194,7 +193,7 @@ and/or `magit-branch-remote-head'."
|
||||
|
||||
(defface magit-keyword-squash
|
||||
'((t :inherit font-lock-warning-face))
|
||||
"Face for squash! and fixup! keywords in commit messages."
|
||||
"Face for squash! and similar keywords in commit messages."
|
||||
:group 'magit-faces)
|
||||
|
||||
(defface magit-signature-good
|
||||
@@ -259,20 +258,20 @@ the current Emacs session.
|
||||
|
||||
If the value is nil, no bindings are added.
|
||||
|
||||
If `default', maybe add:
|
||||
If \\+`default', maybe add:
|
||||
|
||||
C-x g `magit-status'
|
||||
C-x M-g `magit-dispatch'
|
||||
C-c M-g `magit-file-dispatch'
|
||||
\\`C-x' \\`g' `magit-status'
|
||||
\\`C-x' \\`M-g' `magit-dispatch'
|
||||
\\`C-c' \\`M-g' `magit-file-dispatch'
|
||||
|
||||
If `recommended', maybe add:
|
||||
|
||||
C-x g `magit-status'
|
||||
C-c g `magit-dispatch'
|
||||
C-c f `magit-file-dispatch'
|
||||
\\`C-x' \\`g' `magit-status'
|
||||
\\`C-c' \\`g' `magit-dispatch'
|
||||
\\`C-c' \\`f' `magit-file-dispatch'
|
||||
|
||||
These bindings are strongly recommended, but we cannot use
|
||||
them by default, because the \"C-c <LETTER>\" namespace is
|
||||
them by default, because the \\`C-c <LETTER>' namespace is
|
||||
strictly reserved for bindings added by the user.
|
||||
|
||||
The bindings in the chosen set may be added when
|
||||
@@ -440,7 +439,7 @@ This affects `magit-git-command', `magit-git-command-topdir',
|
||||
(defun magit-git-command (command)
|
||||
"Execute COMMAND asynchronously; display output.
|
||||
|
||||
Interactively, prompt for COMMAND in the minibuffer. \"git \" is
|
||||
Interactively, prompt for COMMAND in the minibuffer. \"git \" is
|
||||
used as initial input, but can be deleted to run another command.
|
||||
|
||||
With a prefix argument COMMAND is run in the top-level directory
|
||||
@@ -452,7 +451,7 @@ of the current working tree, otherwise in `default-directory'."
|
||||
(defun magit-git-command-topdir (command)
|
||||
"Execute COMMAND asynchronously; display output.
|
||||
|
||||
Interactively, prompt for COMMAND in the minibuffer. \"git \" is
|
||||
Interactively, prompt for COMMAND in the minibuffer. \"git \" is
|
||||
used as initial input, but can be deleted to run another command.
|
||||
|
||||
COMMAND is run in the top-level directory of the current
|
||||
@@ -482,9 +481,10 @@ is run in the top-level directory of the current working tree."
|
||||
(defun magit--shell-command (command &optional directory)
|
||||
(let ((default-directory (or directory default-directory)))
|
||||
(with-environment-variables (("GIT_PAGER" "cat"))
|
||||
(magit--with-connection-local-variables
|
||||
(magit-start-process shell-file-name nil
|
||||
shell-command-switch command))))
|
||||
(with-connection-local-variables
|
||||
(magit-with-editor
|
||||
(magit-start-process shell-file-name nil
|
||||
shell-command-switch command)))))
|
||||
(magit-process-buffer))
|
||||
|
||||
(defun magit-read-shell-command (&optional toplevel initial-input)
|
||||
@@ -501,20 +501,29 @@ is run in the top-level directory of the current working tree."
|
||||
|
||||
;;; Shared Infix Arguments
|
||||
|
||||
(transient-define-argument magit:--signoff ()
|
||||
:description "Add Signed-off-by trailer"
|
||||
:class 'transient-switch
|
||||
:key "+s"
|
||||
:shortarg "-s"
|
||||
:argument "--signoff"
|
||||
:level 6)
|
||||
|
||||
(transient-define-argument magit:--gpg-sign ()
|
||||
:description "Sign using gpg"
|
||||
:class 'transient-option
|
||||
:shortarg "-S"
|
||||
:argument "--gpg-sign="
|
||||
:allow-empty t
|
||||
:reader #'magit-read-gpg-signing-key)
|
||||
:reader #'magit-read-gpg-signing-key
|
||||
:level 5)
|
||||
|
||||
(defvar magit-gpg-secret-key-hist nil)
|
||||
|
||||
(defun magit-read-gpg-secret-key
|
||||
(prompt &optional initial-input history predicate default)
|
||||
(require 'epa)
|
||||
(let* ((keys (cl-mapcan
|
||||
(let* ((keys (mapcan
|
||||
(lambda (cert)
|
||||
(and (or (not predicate)
|
||||
(funcall predicate cert))
|
||||
@@ -561,6 +570,7 @@ is run in the top-level directory of the current working tree."
|
||||
(1 'font-lock-keyword-face)
|
||||
(2 'font-lock-function-name-face nil t))
|
||||
(,(concat "(" (regexp-opt '("magit-insert-section"
|
||||
"magit-insert-heading"
|
||||
"magit-section-case"
|
||||
"magit-bind-match-strings"
|
||||
"magit-with-temp-index"
|
||||
@@ -579,7 +589,7 @@ is run in the top-level directory of the current working tree."
|
||||
Use the function by the same name instead of this variable.")
|
||||
|
||||
;;;###autoload
|
||||
(defun magit-version (&optional print-dest interactive)
|
||||
(defun magit-version (&optional print-dest interactive nowarn)
|
||||
"Return the version of Magit currently in use.
|
||||
|
||||
If optional argument PRINT-DEST is non-nil, also print the used
|
||||
@@ -597,7 +607,7 @@ the output in the kill ring.
|
||||
'("magit.el" "magit.el.gz")))
|
||||
(let ((load-suffixes (reverse load-suffixes))) ; prefer .el than .elc
|
||||
(setq toplib (locate-library "magit"))))
|
||||
(setq toplib (and toplib (magit--straight-chase-links toplib)))
|
||||
(setq toplib (and toplib (magit--chase-links toplib)))
|
||||
(push toplib debug)
|
||||
(when toplib
|
||||
(let* ((topdir (file-name-directory toplib))
|
||||
@@ -605,7 +615,7 @@ the output in the kill ring.
|
||||
".git" (file-name-directory
|
||||
(directory-file-name topdir))))
|
||||
(static (locate-library "magit-version.el" nil (list topdir)))
|
||||
(static (and static (magit--straight-chase-links static))))
|
||||
(static (and static (magit--chase-links static))))
|
||||
(or (progn
|
||||
(push 'repo debug)
|
||||
(when (and (file-exists-p gitdir)
|
||||
@@ -657,7 +667,7 @@ the output in the kill ring.
|
||||
(if (stringp magit-version)
|
||||
(when print-dest
|
||||
(let ((str (format
|
||||
"Magit %s%s, Transient %s, Git %s, Emacs %s, %s"
|
||||
"Magit %s%s, Transient %s,%s Git %s, Emacs %s, %s"
|
||||
(or magit-version "(unknown)")
|
||||
(or (and (ignore-errors
|
||||
(magit--version>= magit-version "2008"))
|
||||
@@ -679,6 +689,18 @@ the output in the kill ring.
|
||||
(locate-library "transient.el" t))
|
||||
(lm-header "Package-Version"))))
|
||||
"(unknown)")
|
||||
(let ((lib (locate-library "forge.el" t)))
|
||||
(or (and lib
|
||||
(format
|
||||
" Forge %s,"
|
||||
(or (ignore-errors
|
||||
(require 'lisp-mnt)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents lib)
|
||||
(and (fboundp 'lm-header)
|
||||
(lm-header "Package-Version"))))
|
||||
"(unknown)")))
|
||||
""))
|
||||
(magit--safe-git-version)
|
||||
emacs-version
|
||||
system-type)))
|
||||
@@ -689,8 +711,7 @@ the output in the kill ring.
|
||||
(setq magit-version 'error)
|
||||
(when magit-version
|
||||
(push magit-version debug))
|
||||
(unless (equal (getenv "CI") "true")
|
||||
;; The repository is a sparse clone.
|
||||
(unless (or nowarn (equal (getenv "CI") "true"))
|
||||
(message "Cannot determine Magit's version %S" debug)))
|
||||
magit-version))
|
||||
|
||||
@@ -770,7 +791,7 @@ For X11 something like ~/.xinitrc should work.\n"
|
||||
(unless (bound-and-true-p byte-compile-current-file)
|
||||
(if after-init-time
|
||||
(progn (magit-startup-asserts)
|
||||
(magit-version))
|
||||
(magit-version nil nil t))
|
||||
(add-hook 'after-init-hook #'magit-startup-asserts t)
|
||||
(add-hook 'after-init-hook #'magit-version t)))
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user