fordon_greeman / voidfiles

Branch: 2079ec5
Switch branches/tags
main
theidioticdev add emacs 2079ec5 22h ago
817 lines · 31 KB Raw Blame History
1 ;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding:t; coding:utf-8 -*-
2
3 ;; Copyright (C) 2008-2026 The Magit Project Contributors
4
5 ;; Author: Marius Vollmer <marius.vollmer@gmail.com>
6 ;; Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
7 ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
8 ;; Kyle Meyer <kyle@kyleam.com>
9 ;; Former-Maintainers:
10 ;; Nicolas Dudebout <nicolas.dudebout@gatech.edu>
11 ;; Noam Postavsky <npostavs@users.sourceforge.net>
12 ;; Peter J. Weisberg <pj@irregularexpressions.net>
13 ;; Phil Jackson <phil@shellarchive.co.uk>
14 ;; Rémi Vanicat <vanicat@debian.org>
15 ;; Yann Hodique <yann.hodique@gmail.com>
16
17 ;; Homepage: https://github.com/magit/magit
18 ;; Keywords: git tools vc
19
20 ;; Package-Version: 20261101.2154
21 ;; Package-Revision: 942d61d5de37
22 ;; Package-Requires: (
23 ;; (emacs "28.1")
24 ;; (compat "31.0")
25 ;; (cond-let "1.1")
26 ;; (llama "1.0")
27 ;; (magit-section "4.7")
28 ;; (seq "2.24")
29 ;; (transient "0.13")
30 ;; (with-editor "3.5"))
31
32 ;; SPDX-License-Identifier: GPL-3.0-or-later
33
34 ;; Magit is free software: you can redistribute it and/or modify
35 ;; it under the terms of the GNU General Public License as published
36 ;; by the Free Software Foundation, either version 3 of the License,
37 ;; or (at your option) any later version.
38 ;;
39 ;; Magit is distributed in the hope that it will be useful,
40 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
41 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42 ;; GNU General Public License for more details.
43 ;;
44 ;; You should have received a copy of the GNU General Public License
45 ;; along with Magit. If not, see <https://www.gnu.org/licenses/>.
46
47 ;; You should have received a copy of the AUTHORS.md file, which
48 ;; lists all contributors. If not, see https://magit.vc/authors.
49
50 ;;; Commentary:
51
52 ;; Magit is a text-based Git user interface that puts an unmatched focus
53 ;; on streamlining workflows. Commands are invoked using short mnemonic
54 ;; key sequences that take the cursor’s position in the highly actionable
55 ;; interface into account to provide context-sensitive behavior.
56
57 ;; With Magit you can do nearly everything that you can do when using Git
58 ;; on the command-line, but at greater speed and while taking advantage
59 ;; of advanced features that previously seemed too daunting to use on a
60 ;; daily basis. Many users will find that by using Magit they can become
61 ;; more effective Git user.
62
63 ;;; Code:
64
65 (require 'magit-core)
66 (require 'magit-diff)
67 (require 'magit-log)
68 (require 'magit-wip)
69 (require 'magit-apply)
70 (require 'magit-repos)
71 (require 'git-commit)
72
73 (require 'epa) ;used in magit-read-gpg-{secret,signing}-key
74 (require 'with-editor)
75
76 ;;; Options
77
78 (defcustom magit-openpgp-default-signing-key nil
79 "Fingerprint of your default Openpgp key used for signing.
80 If the specified primary key has signing capacity then it is used
81 as the value of the \"--gpg-sign\" argument without prompting, even
82 when other such keys exist. To be able to select another key you
83 must then use a prefix argument."
84 :package-version '(magit . "4.0.0")
85 :group 'magit-commands
86 :type 'string)
87
88 ;;; Faces
89
90 (defface magit-header-line
91 '((t :inherit magit-section-heading))
92 "Face for the `header-line' in some Magit modes.
93 Note that some modes, such as `magit-log-select-mode', have their
94 own faces for the `header-line', or for parts of the
95 `header-line'."
96 :group 'magit-faces)
97
98 (defface magit-header-line-key
99 '((t :inherit font-lock-builtin-face))
100 "Face for keys in the `header-line'."
101 :group 'magit-faces)
102
103 (defface magit-dimmed
104 '((((class color) (background light)) :foreground "grey50")
105 (((class color) (background dark)) :foreground "grey50"))
106 "Face for text that shouldn't stand out."
107 :group 'magit-faces)
108
109 (defface magit-hash
110 '((((class color) (background light)) :foreground "grey60")
111 (((class color) (background dark)) :foreground "grey40"))
112 "Face for the commit object name in the log output."
113 :group 'magit-faces)
114
115 (defface magit-tag
116 '((((class color) (background light)) :foreground "Goldenrod4")
117 (((class color) (background dark)) :foreground "LightGoldenrod2"))
118 "Face for tag labels shown in log buffer."
119 :group 'magit-faces)
120
121 (defface magit-branch-remote
122 '((((class color) (background light)) :foreground "DarkOliveGreen4")
123 (((class color) (background dark)) :foreground "DarkSeaGreen2"))
124 "Face for remote branch head labels shown in log buffer."
125 :group 'magit-faces)
126
127 (defface magit-branch-remote-head
128 '((((supports (:box t))) :inherit magit-branch-remote :box t)
129 (t :inherit magit-branch-remote :inverse-video t))
130 "Face for current branch."
131 :group 'magit-faces)
132
133 (defface magit-branch-local
134 '((((class color) (background light)) :foreground "SkyBlue4")
135 (((class color) (background dark)) :foreground "LightSkyBlue1"))
136 "Face for local branches."
137 :group 'magit-faces)
138
139 (defface magit-branch-current
140 '((((supports (:box t))) :inherit magit-branch-local :box t)
141 (t :inherit magit-branch-local :inverse-video t))
142 "Face for current branch."
143 :group 'magit-faces)
144
145 (defface magit-branch-upstream
146 '((t :slant italic))
147 "Face for upstream branch.
148 This face is only used in logs and it gets combined
149 with `magit-branch-local', `magit-branch-remote'
150 and/or `magit-branch-remote-head'."
151 :group 'magit-faces)
152
153 (defface magit-branch-warning
154 '((t :inherit warning))
155 "Face for warning about (missing) branch."
156 :group 'magit-faces)
157
158 (defface magit-head
159 '((((class color) (background light)) :inherit magit-branch-local)
160 (((class color) (background dark)) :inherit magit-branch-local))
161 "Face for the symbolic ref `HEAD'."
162 :group 'magit-faces)
163
164 (defface magit-refname
165 '((((class color) (background light)) :foreground "grey30")
166 (((class color) (background dark)) :foreground "grey80"))
167 "Face for refnames without a dedicated face."
168 :group 'magit-faces)
169
170 (defface magit-refname-stash
171 '((t :inherit magit-refname))
172 "Face for stash refnames."
173 :group 'magit-faces)
174
175 (defface magit-refname-wip
176 '((t :inherit magit-refname))
177 "Face for wip refnames."
178 :group 'magit-faces)
179
180 (defface magit-refname-pullreq
181 '((t :inherit magit-refname))
182 "Face for pullreq refnames."
183 :group 'magit-faces)
184
185 (defface magit-keyword
186 '((t :inherit font-lock-string-face))
187 "Face for parts of commit messages inside brackets."
188 :group 'magit-faces)
189
190 (defface magit-keyword-squash
191 '((t :inherit font-lock-warning-face))
192 "Face for squash! and similar keywords in commit messages."
193 :group 'magit-faces)
194
195 (defface magit-signature-good
196 '((t :foreground "green"))
197 "Face for good signatures."
198 :group 'magit-faces)
199
200 (defface magit-signature-bad
201 '((t :foreground "red" :weight bold))
202 "Face for bad signatures."
203 :group 'magit-faces)
204
205 (defface magit-signature-untrusted
206 '((t :foreground "medium aquamarine"))
207 "Face for good untrusted signatures."
208 :group 'magit-faces)
209
210 (defface magit-signature-expired
211 '((t :foreground "orange"))
212 "Face for signatures that have expired."
213 :group 'magit-faces)
214
215 (defface magit-signature-expired-key
216 '((t :inherit magit-signature-expired))
217 "Face for signatures made by an expired key."
218 :group 'magit-faces)
219
220 (defface magit-signature-revoked
221 '((t :foreground "violet red"))
222 "Face for signatures made by a revoked key."
223 :group 'magit-faces)
224
225 (defface magit-signature-error
226 '((t :foreground "light blue"))
227 "Face for signatures that cannot be checked (e.g., missing key)."
228 :group 'magit-faces)
229
230 (defface magit-cherry-unmatched
231 '((t :foreground "cyan"))
232 "Face for unmatched cherry commits."
233 :group 'magit-faces)
234
235 (defface magit-cherry-equivalent
236 '((t :foreground "magenta"))
237 "Face for equivalent cherry commits."
238 :group 'magit-faces)
239
240 (defface magit-filename
241 '((t :weight normal))
242 "Face for filenames."
243 :group 'magit-faces)
244
245 ;;; Global Bindings
246
247 ;;;###autoload
248 (defcustom magit-define-global-key-bindings 'default
249 "Which set of key bindings to add to the global keymap, if any.
250
251 This option controls which set of Magit key bindings, if any, may
252 be added to the global keymap, even before Magit is first used in
253 the current Emacs session.
254
255 If the value is nil, no bindings are added.
256
257 If \\+`default', maybe add:
258
259 \\`C-x' \\`g' `magit-status'
260 \\`C-x' \\`M-g' `magit-dispatch'
261 \\`C-c' \\`M-g' `magit-file-dispatch'
262
263 If `recommended', maybe add:
264
265 \\`C-x' \\`g' `magit-status'
266 \\`C-c' \\`g' `magit-dispatch'
267 \\`C-c' \\`f' `magit-file-dispatch'
268
269 These bindings are strongly recommended, but we cannot use
270 them by default, because the \\`C-c <LETTER>' namespace is
271 strictly reserved for bindings added by the user.
272
273 The bindings in the chosen set may be added when
274 `after-init-hook' is run. Each binding is added if, and only
275 if, at that time no other key is bound to the same command,
276 and no other command is bound to the same key. In other words
277 we try to avoid adding bindings that are unnecessary, as well
278 as bindings that conflict with other bindings.
279
280 Adding these bindings is delayed until `after-init-hook' is
281 run to allow users to set the variable anywhere in their init
282 file (without having to make sure to do so before `magit' is
283 loaded or autoloaded) and to increase the likelihood that all
284 the potentially conflicting user bindings have already been
285 added.
286
287 To set this variable use either `setq' or the Custom interface.
288 Do not use the function `customize-set-variable' because doing
289 that would cause Magit to be loaded immediately, when that form
290 is evaluated (this differs from `custom-set-variables', which
291 doesn't load the libraries that define the customized variables).
292
293 Setting this variable has no effect if `after-init-hook' has
294 already been run."
295 :package-version '(magit . "4.0.0")
296 :group 'magit-essentials
297 :type '(choice (const :tag "Add no binding" nil)
298 (const :tag "Use default bindings" default)
299 (const :tag "Use recommended bindings" recommended)))
300
301 ;;;###autoload
302 (progn
303 (defun magit-maybe-define-global-key-bindings (&optional force)
304 "See variable `magit-define-global-key-bindings'."
305 (when magit-define-global-key-bindings
306 (let ((map (current-global-map)))
307 (pcase-dolist (`(,key . ,def)
308 (cond ((eq magit-define-global-key-bindings 'recommended)
309 '(("C-x g" . magit-status)
310 ("C-c g" . magit-dispatch)
311 ("C-c f" . magit-file-dispatch)))
312 ('(("C-x g" . magit-status)
313 ("C-x M-g" . magit-dispatch)
314 ("C-c M-g" . magit-file-dispatch)))))
315 ;; This is autoloaded and thus is used before `compat' is
316 ;; loaded, so we cannot use `keymap-lookup' and `keymap-set'.
317 (when (or force
318 (not (or (lookup-key map (kbd key))
319 (where-is-internal def (make-sparse-keymap) t))))
320 (define-key map (kbd key) def))))))
321 (if after-init-time
322 (magit-maybe-define-global-key-bindings)
323 (add-hook 'after-init-hook #'magit-maybe-define-global-key-bindings t)))
324
325 ;;; Dispatch Menu
326
327 ;;;###autoload(autoload 'magit-dispatch "magit" nil t)
328 (transient-define-prefix magit-dispatch ()
329 "Invoke a Magit command from a list of available commands."
330 :info-manual "(magit)Top"
331 ["Transient and dwim commands"
332 ;; → bound in magit-mode-map or magit-section-mode-map
333 ;; ↓ bound below
334 [("A" "Apply" magit-cherry-pick)
335 ;; a ↓
336 ("b" "Branch" magit-branch)
337 ("B" "Bisect" magit-bisect)
338 ("c" "Commit" magit-commit)
339 ("C" "Clone" magit-clone)
340 ("d" "Diff" magit-diff)
341 ("D" "Diff (change)" magit-diff-refresh)
342 ("e" "Ediff (dwim)" magit-ediff-dwim)
343 ("E" "Ediff" magit-ediff)
344 ("f" "Fetch" magit-fetch)
345 ("F" "Pull" magit-pull)
346 ;; g ↓
347 ;; G → magit-refresh-all
348 ("h" "Help" magit-info)
349 ("H" "Section info" magit-describe-section :if-derived magit-mode)]
350 [("i" "Ignore" magit-gitignore)
351 ("I" "Init" magit-init)
352 ("j" "Jump to section"magit-status-jump :if-mode magit-status-mode)
353 ("j" "Display status" magit-status-quick :if-not-mode magit-status-mode)
354 ("J" "Display buffer" magit-display-repository-buffer)
355 ;; k ↓
356 ;; K → magit-file-untrack
357 ("l" "Log" magit-log)
358 ("L" "Log (change)" magit-log-refresh)
359 ("m" "Merge" magit-merge)
360 ("M" "Remote" magit-remote)
361 ;; n → magit-section-forward
362 ;; N reserved → forge-dispatch
363 ("o" "Submodule" magit-submodule)
364 ("O" "Subtree" magit-subtree)
365 ;; p → magit-section-backward
366 ("P" "Push" magit-push)
367 ;; q → magit-mode-bury-buffer
368 ("Q" "Command" magit-git-command)]
369 [("r" "Rebase" magit-rebase)
370 ;; R → magit-file-rename
371 ;; s ↓
372 ;; S ↓
373 ("t" "Tag" magit-tag)
374 ("T" "Note" magit-notes)
375 ;; u ↓
376 ;; U ↓
377 ;; v ↓
378 ("V" "Revert" magit-revert)
379 ("w" "Apply patches" magit-am)
380 ("W" "Format patches" magit-patch)
381 ;; x → magit-reset-quickly
382 ("X" "Reset" magit-reset)
383 ("y" "Show Refs" magit-show-refs)
384 ("Y" "Cherries" magit-cherry)
385 ("z" "Stash" magit-stash)
386 ("Z" "Worktree" magit-worktree)
387 ("!" "Run" magit-run)]]
388 ["Applying changes"
389 :if-derived magit-mode
390 [("a" "Apply" magit-apply)
391 ("v" "Reverse" magit-reverse)
392 ("k" "Discard" magit-discard)]
393 [("s" "Stage" magit-stage)
394 ("u" "Unstage" magit-unstage)]
395 [("S" "Stage all" magit-stage-modified)
396 ("U" "Unstage all" magit-unstage-all)]]
397 ["Essential commands"
398 :if-derived magit-mode
399 [("g" " Refresh current buffer" magit-refresh)
400 ("q" " Bury current buffer" magit-mode-bury-buffer)
401 ("<tab>" " Toggle section at point" magit-section-toggle)
402 ("<return>" "Visit thing at point" magit-visit-thing)]
403 [("C-x m" "Show all key bindings" describe-mode)
404 ("C-x i" "Show Info manual" magit-info)]])
405
406 ;;; Git Menu
407
408 (defcustom magit-shell-command-verbose-prompt t
409 "Whether to show the working directory when reading a command.
410 This affects `magit-git-command', `magit-git-command-topdir',
411 `magit-shell-command', and `magit-shell-command-topdir'."
412 :package-version '(magit . "2.11.0")
413 :group 'magit-commands
414 :type 'boolean)
415
416 (defvar magit-git-command-history nil)
417
418 ;;;###autoload(autoload 'magit-run "magit" nil t)
419 (transient-define-prefix magit-run ()
420 "Run git or another command, or launch a graphical utility."
421 [["Run git subcommand"
422 ("!" "in repository root" magit-git-command-topdir)
423 ("p" "in working directory" magit-git-command)]
424 ["Run shell command"
425 ("s" "in repository root" magit-shell-command-topdir)
426 ("S" "in working directory" magit-shell-command)]
427 ["Launch"
428 ("k" "gitk" magit-run-gitk)
429 ("a" "gitk --all" magit-run-gitk-all)
430 ("b" "gitk --branches" magit-run-gitk-branches)
431 ("g" "git gui" magit-run-git-gui)
432 ("m" "git mergetool --gui" magit-git-mergetool)]])
433
434 ;;;###autoload
435 (defun magit-git-command (command)
436 "Execute COMMAND asynchronously; display output.
437
438 Interactively, prompt for COMMAND in the minibuffer. \"git \" is
439 used as initial input, but can be deleted to run another command.
440
441 With a prefix argument COMMAND is run in the top-level directory
442 of the current working tree, otherwise in `default-directory'."
443 (interactive (list (magit-read-shell-command nil "git ")))
444 (magit--shell-command command))
445
446 ;;;###autoload
447 (defun magit-git-command-topdir (command)
448 "Execute COMMAND asynchronously; display output.
449
450 Interactively, prompt for COMMAND in the minibuffer. \"git \" is
451 used as initial input, but can be deleted to run another command.
452
453 COMMAND is run in the top-level directory of the current
454 working tree."
455 (interactive (list (magit-read-shell-command t "git ")))
456 (magit--shell-command command (magit-toplevel)))
457
458 ;;;###autoload
459 (defun magit-shell-command (command)
460 "Execute COMMAND asynchronously; display output.
461
462 Interactively, prompt for COMMAND in the minibuffer. With a
463 prefix argument COMMAND is run in the top-level directory of
464 the current working tree, otherwise in `default-directory'."
465 (interactive (list (magit-read-shell-command)))
466 (magit--shell-command command))
467
468 ;;;###autoload
469 (defun magit-shell-command-topdir (command)
470 "Execute COMMAND asynchronously; display output.
471
472 Interactively, prompt for COMMAND in the minibuffer. COMMAND
473 is run in the top-level directory of the current working tree."
474 (interactive (list (magit-read-shell-command t)))
475 (magit--shell-command command (magit-toplevel)))
476
477 (defun magit--shell-command (command &optional directory)
478 (let ((default-directory (or directory default-directory)))
479 (with-environment-variables (("GIT_PAGER" "cat"))
480 (with-connection-local-variables
481 (magit-with-editor
482 (magit-start-process shell-file-name nil
483 shell-command-switch command)))))
484 (magit-process-buffer))
485
486 (defun magit-read-shell-command (&optional toplevel initial-input)
487 (let ((default-directory
488 (if (or toplevel current-prefix-arg)
489 (or (magit-toplevel)
490 (magit--not-inside-repository-error))
491 default-directory)))
492 (read-shell-command (if magit-shell-command-verbose-prompt
493 (format "Async shell command in %s: "
494 (abbreviate-file-name default-directory))
495 "Async shell command: ")
496 initial-input 'magit-git-command-history)))
497
498 ;;; Shared Infix Arguments
499
500 (transient-define-argument magit:--signoff ()
501 :description "Add Signed-off-by trailer"
502 :class 'transient-switch
503 :key "+s"
504 :shortarg "-s"
505 :argument "--signoff"
506 :level 6)
507
508 (transient-define-argument magit:--gpg-sign ()
509 :description (##concat "Sign using " (or (magit-get "gpg.format") "openpgp"))
510 :class 'transient-option
511 :shortarg "-S"
512 :argument "--gpg-sign="
513 :allow-empty t
514 :reader #'magit-read-gpg-signing-key
515 :level 5)
516
517 (defvar magit-gpg-secret-key-hist nil)
518
519 (defun magit-read-gpg-secret-key
520 (prompt &optional initial-input history predicate default)
521 (require 'epa)
522 (let* ((keys (seq-keep
523 (lambda (cert)
524 (and (or (not predicate)
525 (funcall predicate cert))
526 (let* ((key (car (epg-key-sub-key-list cert)))
527 (fpr (epg-sub-key-fingerprint key))
528 (id (epg-sub-key-id key))
529 (author
530 (and-let ((id-obj
531 (car (epg-key-user-id-list cert))))
532 (let ((id-str (epg-user-id-string id-obj)))
533 (if (stringp id-str)
534 id-str
535 (epg-decode-dn id-obj))))))
536 (propertize fpr 'display
537 (concat (substring fpr 0 (- (length id)))
538 (propertize id 'face 'highlight)
539 " " author)))))
540 (epg-list-keys (epg-make-context epa-protocol) nil t)))
541 (choice (or (and (not current-prefix-arg)
542 (or (and (length= keys 1) (car keys))
543 (and default (car (member default keys)))))
544 (completing-read prompt keys nil nil nil
545 history nil initial-input))))
546 (set-text-properties 0 (length choice) nil choice)
547 choice))
548
549 (defun magit-read-gpg-signing-key (prompt &optional initial-input history)
550 (if (member (magit-get "gpg.format") '(nil "openpgp"))
551 (magit-read-gpg-secret-key
552 prompt initial-input history
553 (lambda (cert)
554 (seq-some (##memq 'sign (epg-sub-key-capability %))
555 (epg-key-sub-key-list cert)))
556 magit-openpgp-default-signing-key)
557 ""))
558
559 ;;; Font-Lock Keywords
560
561 (defconst magit-font-lock-keywords
562 (eval-when-compile
563 `((,(concat "(\\(magit-define-section-jumper\\)\\_>"
564 "[ \t'(]*"
565 "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
566 (1 'font-lock-keyword-face)
567 (2 'font-lock-function-name-face nil t))
568 (,(concat "(" (regexp-opt '("magit-insert-section"
569 "magit-insert-heading"
570 "magit-section-case"
571 "magit-bind-match-strings"
572 "magit-with-temp-index"
573 "magit-with-blob"
574 "magit-with-toplevel")
575 t)
576 "\\_>")
577 . 1))))
578
579 (font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords)
580
581 ;;; Version
582
583 (defvar magit-version #'undefined
584 "The version of Magit that you're using.
585 Use the function by the same name instead of this variable.")
586
587 ;;;###autoload
588 (defun magit-version (&optional print-dest interactive nowarn)
589 "Return the version of Magit currently in use.
590
591 If optional argument PRINT-DEST is non-nil, also print the used
592 versions of Magit, Transient, Git and Emacs to the output stream
593 selected by that argument. Interactively use the echo area, or
594 with a prefix argument use the current buffer. Additionally put
595 the output in the kill ring.
596 \n(fn &optional PRINT-DEST)"
597 (interactive (list (if current-prefix-arg (current-buffer) t) t))
598 (let ((magit-git-global-arguments nil)
599 (toplib (or load-file-name buffer-file-name))
600 debug)
601 (unless (and toplib
602 (member (file-name-nondirectory toplib)
603 '("magit.el" "magit.el.gz")))
604 (let ((load-suffixes (reverse load-suffixes))) ; prefer .el than .elc
605 (setq toplib (locate-library "magit"))))
606 (setq toplib (and toplib (magit--chase-links toplib)))
607 (push toplib debug)
608 (when toplib
609 (let* ((topdir (file-name-directory toplib))
610 (gitdir (expand-file-name
611 ".git" (file-name-parent-directory topdir)))
612 (static (locate-library "magit-version.el" nil (list topdir)))
613 (static (and static (magit--chase-links static))))
614 (or (progn
615 (push 'repo debug)
616 (when (and (file-exists-p gitdir)
617 ;; It is a repo, but is it the Magit repo?
618 (file-exists-p
619 (expand-file-name "../lisp/magit.el" gitdir)))
620 (push t debug)
621 ;; Inside the repo the version file should only exist
622 ;; while running make.
623 (when (and static (not noninteractive))
624 (ignore-errors (delete-file static)))
625 (setq magit-version
626 (let ((default-directory topdir))
627 (magit-git-string "describe"
628 "--tags" "--dirty" "--always")))))
629 (progn
630 (push 'static debug)
631 (when (and static (file-exists-p static))
632 (push t debug)
633 (load-file static)
634 magit-version))
635 (when (and (featurep 'package)
636 (boundp 'package-alist)
637 (fboundp 'package-version-join))
638 (push 'elpa debug)
639 (ignore-errors
640 (when-let ((version (cadr (assq 'magit package-alist))))
641 (push t debug)
642 (setq magit-version
643 (and (fboundp 'package-desc-version)
644 (package-version-join
645 (package-desc-version version)))))))
646 (progn
647 (push 'dirname debug)
648 (let ((dirname (file-name-nondirectory
649 (directory-file-name topdir))))
650 (when (string-match "\\`magit-\\([0-9].*\\)" dirname)
651 (setq magit-version (match-str 1 dirname)))))
652 ;; If all else fails, just report the commit hash. It's
653 ;; better than nothing and we cannot do better in the case
654 ;; of e.g., a shallow clone.
655 (progn
656 (push 'hash debug)
657 ;; Same check as above to see if it's really the Magit repo.
658 (when (and (file-exists-p gitdir)
659 (file-exists-p
660 (expand-file-name "../lisp/magit.el" gitdir)))
661 (setq magit-version
662 (let ((default-directory topdir))
663 (magit-git-string "rev-parse" "HEAD"))))))))
664 (if (stringp magit-version)
665 (when print-dest
666 (let* ((alt (or (and (ignore-errors
667 (magit--version>= magit-version "2008"))
668 (ignore-errors
669 (require 'lisp-mnt)
670 (and (fboundp 'lm-header)
671 (with-temp-buffer
672 (insert-file-contents
673 (locate-library "magit.el" t))
674 (lm-header "Package-Version")))))))
675 (str (format
676 "Magit %s%s, Transient %s,%s Git %s, Emacs %s, %s"
677 (or magit-version "(unknown)")
678 (if (and alt (not (equal alt magit-version)))
679 (format " [>= %s]" alt)
680 "")
681 (or (ignore-errors
682 (require 'lisp-mnt)
683 (and (fboundp 'lm-header)
684 (with-temp-buffer
685 (insert-file-contents
686 (locate-library "transient.el" t))
687 (lm-header "Package-Version"))))
688 "(unknown)")
689 (let ((lib (locate-library "forge.el" t)))
690 (or (and lib
691 (format
692 " Forge %s,"
693 (or (ignore-errors
694 (require 'lisp-mnt)
695 (with-temp-buffer
696 (insert-file-contents lib)
697 (and (fboundp 'lm-header)
698 (lm-header "Package-Version"))))
699 "(unknown)")))
700 ""))
701 (magit--safe-git-version)
702 emacs-version
703 system-type)))
704 (when interactive
705 (kill-new str))
706 (princ str print-dest)))
707 (setq debug (reverse debug))
708 (setq magit-version 'error)
709 (when magit-version
710 (push magit-version debug))
711 (unless (or nowarn (equal (getenv "CI") "true"))
712 (message "Cannot determine Magit's version %S" debug)))
713 magit-version))
714
715 ;;; Startup Asserts
716
717 (defun magit-startup-asserts ()
718 (when-let ((val (getenv "GIT_DIR")))
719 (setenv "GIT_DIR")
720 (message
721 "Magit unset $GIT_DIR (was %S). See %s" val
722 ;; Note: Pass URL as argument rather than embedding in the format
723 ;; string to prevent the single quote from being rendered
724 ;; according to `text-quoting-style'.
725 "https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike"))
726 (when-let ((val (getenv "GIT_WORK_TREE")))
727 (setenv "GIT_WORK_TREE")
728 (message
729 "Magit unset $GIT_WORK_TREE (was %S). See %s" val
730 ;; See comment above.
731 "https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike"))
732 ;; Git isn't required while building Magit.
733 (unless (bound-and-true-p byte-compile-current-file)
734 (magit-git-version-assert))
735 (when (version< emacs-version magit--minimal-emacs)
736 (display-warning 'magit (format "\
737 Magit requires Emacs >= %s, you are using %s.
738
739 If this comes as a surprise to you, because you do actually have
740 a newer version installed, then that probably means that the
741 older version happens to appear earlier on the `$PATH'. If you
742 always start Emacs from a shell, then that can be fixed in the
743 shell's init file. If you start Emacs by clicking on an icon,
744 or using some sort of application launcher, then you probably
745 have to adjust the environment as seen by graphical interface.
746 For X11 something like ~/.xinitrc should work.\n"
747 magit--minimal-emacs emacs-version)
748 :error)))
749
750 ;;; Loading Libraries
751
752 (provide 'magit)
753
754 (cl-eval-when (load eval)
755 (require 'magit-status)
756 (require 'magit-refs)
757 (require 'magit-files)
758 (require 'magit-reset)
759 (require 'magit-branch)
760 (require 'magit-merge)
761 (require 'magit-tag)
762 (require 'magit-worktree)
763 (require 'magit-notes)
764 (require 'magit-sequence)
765 (require 'magit-commit)
766 (require 'magit-remote)
767 (require 'magit-clone)
768 (require 'magit-fetch)
769 (require 'magit-pull)
770 (require 'magit-push)
771 (require 'magit-bisect)
772 (require 'magit-stash)
773 (require 'magit-blame)
774 (require 'magit-submodule)
775 (unless (or noninteractive
776 ;; The `provide' form may be missing, so we have to
777 ;; try harder to ensure this is loaded exactly once.
778 (featurep 'magit-autoloads)
779 (autoloadp (symbol-function 'magit-patch))
780 (load "magit-autoloads" t t))
781 (require 'magit-patch)
782 (require 'magit-subtree)
783 (require 'magit-ediff)
784 (require 'magit-gitignore)
785 (require 'magit-sparse-checkout)
786 (require 'magit-extras)
787 (require 'magit-dired)
788 (require 'git-rebase)
789 (require 'magit-bookmark)))
790
791 (with-eval-after-load 'bookmark
792 (require 'magit-bookmark))
793
794 (unless (bound-and-true-p byte-compile-current-file)
795 (if after-init-time
796 (progn (magit-startup-asserts)
797 (magit-version nil nil t))
798 (add-hook 'after-init-hook #'magit-startup-asserts t)
799 (add-hook 'after-init-hook #'magit-version t)))
800
801 ;; Local Variables:
802 ;; read-symbol-shorthands: (
803 ;; ("and$" . "cond-let--and$")
804 ;; ("thread$" . "cond-let--thread$")
805 ;; ("when$" . "cond-let--when$")
806 ;; ("and-let*" . "cond-let--and-let*")
807 ;; ("and-let" . "cond-let--and-let")
808 ;; ("if-let*" . "cond-let--if-let*")
809 ;; ("if-let" . "cond-let--if-let")
810 ;; ("when-let*" . "cond-let--when-let*")
811 ;; ("when-let" . "cond-let--when-let")
812 ;; ("while-let*" . "cond-let--while-let*")
813 ;; ("while-let" . "cond-let--while-let")
814 ;; ("match-string" . "match-string")
815 ;; ("match-str" . "match-string-no-properties"))
816 ;; End:
817 ;;; magit.el ends here